-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b8de8cd
commit 08cad37
Showing
14 changed files
with
519 additions
and
147 deletions.
There are no files selected for viewing
4 changes: 2 additions & 2 deletions
4
docs/docs/tutorial-extras/_category_.json → docs/docs/advanced/_category_.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
# Authenticators | ||
|
||
RestSharp includes authenticators for basic HTTP, OAuth1 and token-based (JWT and OAuth2). | ||
|
||
There are two ways to set the authenticator: client-wide or per-request. | ||
|
||
Set the client-wide authenticator by assigning the `Authenticator` property of `RestClientOptions`: | ||
|
||
```csharp | ||
var options = new RestClientOptions("http://example.com") { | ||
Authenticator = new HttpBasicAuthenticator("username", "password") | ||
}; | ||
var client = new RestClient(options); | ||
``` | ||
|
||
To set the authenticator per-request, assign the `Authenticator` property of `RestRequest`: | ||
|
||
```csharp | ||
var request = new RestRequest("/api/users/me") { | ||
Authenticator = new HttpBasicAuthenticator("username", "password") | ||
}; | ||
var response = await client.ExecuteAsync(request, cancellationToken); | ||
``` | ||
|
||
## Basic Authentication | ||
|
||
The `HttpBasicAuthenticator` allows you pass a username and password as a basic `Authorization` header using a base64 encoded string. | ||
|
||
```csharp | ||
var options = new RestClientOptions("http://example.com") { | ||
Authenticator = new HttpBasicAuthenticator("username", "password") | ||
}; | ||
var client = new RestClient(options); | ||
``` | ||
|
||
## OAuth1 | ||
|
||
For OAuth1 authentication the `OAuth1Authenticator` class provides static methods to help generate an OAuth authenticator. | ||
|
||
### Request token | ||
|
||
This method requires a `consumerKey` and `consumerSecret` to authenticate. | ||
|
||
```csharp | ||
var options = new RestClientOptions("http://example.com") { | ||
Authenticator = OAuth1Authenticator.ForRequestToken(consumerKey, consumerSecret) | ||
}; | ||
var client = new RestClient(options); | ||
``` | ||
|
||
### Access token | ||
|
||
This method retrieves an access token when provided `consumerKey`, `consumerSecret`, `oauthToken`, and `oauthTokenSecret`. | ||
|
||
```csharp | ||
var authenticator = OAuth1Authenticator.ForAccessToken( | ||
consumerKey, consumerSecret, oauthToken, oauthTokenSecret | ||
); | ||
var options = new RestClientOptions("http://example.com") { | ||
Authenticator = authenticator | ||
}; | ||
var client = new RestClient(options); | ||
``` | ||
|
||
This method also includes an optional parameter to specify the `OAuthSignatureMethod`. | ||
```csharp | ||
var authenticator = OAuth1Authenticator.ForAccessToken( | ||
consumerKey, consumerSecret, oauthToken, oauthTokenSecret, | ||
OAuthSignatureMethod.PlainText | ||
); | ||
``` | ||
|
||
### 0-legged OAuth | ||
|
||
The same access token authenticator can be used in 0-legged OAuth scenarios by providing `null` for the `consumerSecret`. | ||
|
||
```csharp | ||
var authenticator = OAuth1Authenticator.ForAccessToken( | ||
consumerKey, null, oauthToken, oauthTokenSecret | ||
); | ||
``` | ||
|
||
## OAuth2 | ||
|
||
RestSharp has two very simple authenticators to send the access token as part of the request. | ||
|
||
`OAuth2UriQueryParameterAuthenticator` accepts the access token as the only constructor argument, and it will send the provided token as a query parameter `oauth_token`. | ||
|
||
`OAuth2AuthorizationRequestHeaderAuthenticator` has two constructors. One only accepts a single argument, which is the access token. The other constructor also allows you to specify the token type. The authenticator will then add an `Authorization` header using the specified token type or `OAuth` as the default token type, and the token itself. | ||
|
||
For example: | ||
|
||
```csharp | ||
var authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator( | ||
token, "Bearer" | ||
); | ||
var options = new RestClientOptions("http://example.com") { | ||
Authenticator = authenticator | ||
}; | ||
var client = new RestClient(options); | ||
``` | ||
|
||
The code above will tell RestSharp to send the bearer token with each request as a header. Essentially, the code above does the same as the sample for `JwtAuthenticator` below. | ||
|
||
As those authenticators don't do much to get the token itself, you might be interested in looking at our [sample OAuth2 authenticator](usage.md#authenticator), which requests the token on its own. | ||
|
||
## JWT | ||
|
||
The JWT authentication can be supported by using `JwtAuthenticator`. It is a very simple class that can be constructed like this: | ||
|
||
```csharp | ||
var authenticator = new JwtAuthenticator(myToken); | ||
var options = new RestClientOptions("http://example.com") { | ||
Authenticator = authenticator | ||
}; | ||
var client = new RestClient(options); | ||
``` | ||
|
||
For each request, it will add an `Authorization` header with the value `Bearer <your token>`. | ||
|
||
As you might need to refresh the token from, you can use the `SetBearerToken` method to update the token. | ||
|
||
## Custom Authenticator | ||
|
||
You can write your own implementation by implementing `IAuthenticator` and | ||
registering it with your RestClient: | ||
|
||
```csharp | ||
var authenticator = new SuperAuthenticator(); // implements IAuthenticator | ||
var options = new RestClientOptions("http://example.com") { | ||
Authenticator = authenticator | ||
}; | ||
var client = new RestClient(options); | ||
``` | ||
|
||
The `Authenticate` method is the very first thing called upon calling `RestClient.Execute` or `RestClient.Execute<T>`. | ||
It gets the `RestRequest` currently being executed giving you access to every part of the request data (headers, parameters, etc.) | ||
|
||
You can find an example of a custom authenticator that fetches and uses an OAuth2 bearer token [here](usage.md#authenticator). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Error handling | ||
|
||
If there is a network transport error (network is down, failed DNS lookup, etc), or any kind of server error (except 404), `RestResponse.ResponseStatus` will be set to `ResponseStatus.Error`, otherwise it will be `ResponseStatus.Completed`. | ||
|
||
If an API returns a 404, `ResponseStatus` will still be `Completed`. If you need access to the HTTP status code returned you will find it at `RestResponse.StatusCode`. | ||
The `Status` property is an indicator of completion independent of the API error handling. | ||
|
||
Normally, RestSharp doesn't throw an exception if the request fails. | ||
|
||
However, it is possible to configure RestSharp to throw in different situations, when it normally doesn't throw | ||
in favour of giving you the error as a property. | ||
|
||
| Property | Behavior | | ||
|-------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||
| `FailOnDeserializationError` | Changes the default behavior when failed deserialization results in a successful response with an empty `Data` property of the response. Setting this property to `true` will tell RestSharp to consider failed deserialization as an error and set the `ResponseStatus` to `Error` accordingly. | | ||
| `ThrowOnDeserializationError` | Changes the default behavior when failed deserialization results in empty `Data` property of the response. Setting this property to `true` will tell RestSharp to throw when deserialization fails. | | ||
| `ThrowOnAnyError` | Setting this property to `true` changes the default behavior and forces RestSharp to throw if any errors occurs when making a request or during deserialization. | | ||
|
||
Those properties are available for the `RestClientOptions` and will be used for all request made with the client instance. | ||
|
||
For example, you can configure the client to throw an exception if any error occurs when making a request, or when a request returns a non-successful HTTP status code: | ||
|
||
```csharp | ||
var options = new RestClientOptions(url) { | ||
ThrowOnAnyError = true | ||
}; | ||
var client = new RestClient(options); | ||
var request = new RestRequest("resource/{id}").AddUrlSegment("id", 123); | ||
// 👇 will throw if the request fails | ||
var response = await client.ExecuteGetAsync<ResponseModel>(request); | ||
``` | ||
|
||
:::warning | ||
Please be aware that deserialization failures will only work if the serializer throws an exception when deserializing the response. | ||
Many serializers don't throw by default, and just return a `null` result. RestSharp is unable to figure out why `null` is returned, so it won't fail in this case. | ||
Check the serializer documentation to find out if it can be configured to throw on deserialization error. | ||
::: | ||
|
||
There are also slight differences on how different overloads handle exceptions. | ||
|
||
Asynchronous generic methods `GetAsync<T>`, `PostAsync<T>` and so on, which aren't a part of `RestClient` interface (those methods are extension methods) return `Task<T>`. It means that there's no `RestResponse` to set the response status to error. We decided to throw an exception when such a request fails. It is a trade-off between the API consistency and usability of the library. Usually, you only need the content of `RestResponse` instance to diagnose issues and most of the time the exception would tell you what's wrong. | ||
|
||
Below, you can find how different extensions deal with errors. Note that functions, which don't throw by default, will throw exceptions when `ThrowOnAnyError` is set to `true`. | ||
|
||
| Function | Throws on errors | | ||
|:----------------------|:-----------------| | ||
| `ExecuteAsync` | No | | ||
| `ExecuteGetAsync` | No | | ||
| `ExecuteGetAsync<T>` | No | | ||
| `ExecutePostAsync` | No | | ||
| `ExecutePostAsync<T>` | No | | ||
| `ExecutePutAsync` | No | | ||
| `ExecutePutAsync<T>` | No | | ||
| `GetAsync` | Yes | | ||
| `GetAsync<T>` | Yes | | ||
| `PostAsync` | Yes | | ||
| `PostAsync<T>` | Yes | | ||
| `PatchAsync` | Yes | | ||
| `PatchAsync<T>` | Yes | | ||
| `DeleteAsync` | Yes | | ||
| `DeleteAsync<T>` | Yes | | ||
| `OptionsAsync` | Yes | | ||
| `OptionsAsync<T>` | Yes | | ||
| `HeadAsync` | Yes | | ||
| `HeadAsync<T>` | Yes | | ||
|
||
In addition, all the functions for JSON requests, like `GetJsonAsync` and `PostJsonAsync` throw an exception if the HTTP call fails. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
--- | ||
title: Interceptors | ||
--- | ||
|
||
## Intercepting requests and responses | ||
|
||
Interceptors are a powerful feature of RestSharp that allows you to modify requests and responses before they are sent or received. You can use interceptors to add headers, modify the request body, or even cancel the request. You can also use interceptors to modify the response before it is returned to the caller. | ||
|
||
### Implementing an interceptor | ||
|
||
To implement an interceptor, you need to create a class that inherits the `Interceptor` base class. The base class implements all interceptor methods as virtual, so you can override them in your derived class. | ||
|
||
Methods that you can override are: | ||
- `BeforeRequest(RestRequest request, CancellationToken cancellationToken)` | ||
- `AfterRequest(RestResponse response, CancellationToken cancellationToken)` | ||
- `BeforeHttpRequest(HttpRequestMessage requestMessage, CancellationToken cancellationToken)` | ||
- `AfterHttpResponse(HttpResponseMessage responseMessage, CancellationToken cancellationToken)` | ||
- `BeforeDeserialization(RestResponse response, CancellationToken cancellationToken)` | ||
|
||
All those functions must return a `ValueTask` instance. | ||
|
||
Here's an example of an interceptor that adds a header to a request: | ||
|
||
```csharp | ||
// This interceptor adds a header to the request | ||
// You'd not normally use this interceptor, as RestSharp already has a method | ||
// to add headers to the request | ||
class HeaderInterceptor(string headerName, string headerValue) : Interceptors.Interceptor { | ||
public override ValueTask BeforeHttpRequest(HttpRequestMessage requestMessage, CancellationToken cancellationToken) { | ||
requestMessage.Headers.Add(headerName, headerValue); | ||
return ValueTask.CompletedTask; | ||
} | ||
} | ||
``` | ||
|
||
Because interceptor functions return `ValueTask`, you can use `async` and `await` inside them. | ||
|
||
### Using an interceptor | ||
|
||
It's possible to add as many interceptors as you want, both to the client and to the request. The interceptors are executed in the order they were added. | ||
|
||
Adding interceptors to the client is done via the client options: | ||
|
||
```csharp | ||
var options = new RestClientOptions("https://api.example.com") { | ||
Interceptors = [new HeaderInterceptor("Authorization", token)] | ||
}; | ||
var client = new RestClient(options); | ||
``` | ||
|
||
When you add an interceptor to the client, it will be executed for every request made by that client. | ||
|
||
You can also add an interceptor to a specific request: | ||
|
||
```csharp | ||
var request = new RestRequest("resource") { | ||
Interceptors = [new HeaderInterceptor("Authorization", token)] | ||
}; | ||
``` | ||
|
||
In this case, the interceptor will only be executed for that specific request. | ||
|
||
### Deprecation notice | ||
|
||
Interceptors aim to replace the existing request hooks available in RestSharp prior to version 111.0. Those hooks are marked with `Obsolete` attribute and will be removed in the future. If you are using those hooks, we recommend migrating to interceptors as soon as possible. | ||
|
||
To make the migration easier, RestSharp provides a class called `CompatibilityInterceptor`. It has properties for the hooks available in RestSharp 110.0 and earlier. You can use it to migrate your code to interceptors without changing the existing logic. | ||
|
||
For example, a code that uses `OnBeforeRequest` hook: | ||
|
||
```csharp | ||
var request = new RestRequest("success"); | ||
request.OnBeforeDeserialization += _ => throw new Exception(exceptionMessage); | ||
``` | ||
|
||
Can be migrated to interceptors like this: | ||
|
||
```csharp | ||
var request = new RestRequest("success") { | ||
Interceptors = [new CompatibilityInterceptor { | ||
OnBeforeDeserialization = _ => throw new Exception(exceptionMessage) | ||
}] | ||
}; | ||
``` |
Oops, something went wrong.