docs: add metadata documentation to httpClient (#41706)

PR Close #41706
This commit is contained in:
Kapunahele Wong 2021-04-16 16:02:42 -04:00 committed by Jessica Janiuk
parent e47ea2959c
commit 09abee359d
2 changed files with 98 additions and 1 deletions

View File

@ -0,0 +1,50 @@
// #docplaster
import {HttpClient, HttpContext, HttpContextToken, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs';
/*
// #docregion reading-context
import {retry} from 'rxjs';
// #enddocregion reading-context
*/
// #docregion mutable-context
import {retry, tap} from 'rxjs/operators';
// #enddocregion mutable-context
// #docregion context-token, mutable-context
export const RETRY_COUNT = new HttpContextToken(() => 3);
// #enddocregion context-token
export const ERROR_COUNT = new HttpContextToken(() => 0);
// #enddocregion mutable-context
export class FakeService {
constructor(private httpClient: HttpClient) {
// #docregion set-context
this.httpClient
.get('/data/feed', {
context: new HttpContext().set(RETRY_COUNT, 5),
})
.subscribe(results => {/* ... */});
// #enddocregion set-context
}
}
// #docregion reading-context, mutable-context
export class RetryInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const retryCount = req.context.get(RETRY_COUNT);
return next.handle(req).pipe(
// #enddocregion reading-context
tap(null,
() => {
// An error has occurred, so increment this request's ERROR_COUNT.
req.set(ERROR_COUNT, req.get(ERROR_COUNT) + 1);
}),
// #docregion reading-context
// Retry the request a configurable number of times.
retry(retryCount),
);
}
}
// #enddocregion reading-context, mutable-context

View File

@ -812,7 +812,7 @@ Neither `tap` nor `finalize` touch the values of the observable stream returned
Interceptors can be used to replace the built-in JSON parsing with a custom implementation. Interceptors can be used to replace the built-in JSON parsing with a custom implementation.
The `CustomJsonInterceptor` in the following example demonstrates how to achieve this. The `CustomJsonInterceptor` in the following example demonstrates how to achieve this.
If the intercepted request expects a `'json'` response, the `reponseType` is changed to `'text'` If the intercepted request expects a `'json'` response, the `responseType` is changed to `'text'`
to disable the built-in JSON parsing. Then the response is parsed via the injected `JsonParser`. to disable the built-in JSON parsing. Then the response is parsed via the injected `JsonParser`.
<code-example <code-example
@ -1197,3 +1197,50 @@ Alternatively, you can call `request.error()` with an `ErrorEvent`.
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="network-error"> region="network-error">
</code-example> </code-example>
## Passing metadata to interceptors
Many interceptors require or benefit from configuration. Consider an interceptor that retries failed requests.
By default, the interceptor might retry a request three times, but you might want to override this retry count for particularly error-prone or sensitive requests.
`HttpClient` requests contain a _context_ that can carry metadata about the request.
This context is available for interceptors to read or modify, though it is not transmitted to the backend server when the request is sent.
This allows applications or other interceptors to tag requests with configuration parameters, such as how many times to retry a request.
### Creating a context token
Angular stores and retrieves a value in the context using an `HttpContextToken`.
You can create a context token using the `new` operator, as in the following example:
<code-example path="http/src/app/http-interceptors/retry-interceptor.ts" region="context-token" header="creating a context token"></code-example>
The lambda function `() => 3` passed during the creation of the `HttpContextToken` serves two purposes:
1. It allows TypeScript to infer the type of this token: `HttpContextToken<number>`.
The request context is type-safe&mdash;reading a token from a request's context returns a value of the appropriate type.
1. It sets the default value for the token.
This is the value that the request context returns if no other value has been set for this token.
Using a default value avoids the need to check if a particular value is set.
### Setting context values when making a request
When making a request, you can provide an `HttpContext` instance, in which you have already set the context values.
<code-example path="http/src/app/http-interceptors/retry-interceptor.ts" region="set-context" header="setting context values"></code-example>
### Reading context values in an interceptor
Within an interceptor, you can read the value of a token in a given request's context with `HttpContext.get()`.
If you have not explicitly set a value for the token, Angular returns the default value specified in the token.
<code-example path="http/src/app/http-interceptors/retry-interceptor.ts" region="reading-context" header="reading context values in an interceptor"></code-example>
### Contexts are mutable
Unlike most other aspects of `HttpRequest` instances, the request context is mutable and persists across other immutable transformations of the request.
This allows interceptors to coordinate operations through the context.
For instance, the `RetryInterceptor` example could use a second context token to track how many errors occur during the execution of a given request:
<code-example path="http/src/app/http-interceptors/retry-interceptor.ts" region="mutable-context" header="coordinating operations through the context"></code-example>