mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
The "Providing HttpClient through dependency injection" documentation now shows that in case of a standalone boostraped app, the provideHttpClient is to include in the app.config.ts file. Also updated the http setup server communication example to align the new doc (adev) with the old one (aio). PR Close #52806
263 lines
11 KiB
Markdown
263 lines
11 KiB
Markdown
# HTTP Server communication
|
|
|
|
<div class="callout is-critical">
|
|
|
|
<header>Marked for archiving</header>
|
|
|
|
To ensure that you have the best experience possible, this topic is marked for archiving until we determine that it clearly conveys the most accurate information possible.
|
|
|
|
In the meantime, this topic might be helpful: [Understanding HTTP](guide/understanding-communicating-with-http).
|
|
|
|
If you think this content should not be archived, please file a [GitHub issue](https://github.com/angular/angular/issues/new?template=3-docs-bug.md).
|
|
|
|
</div>
|
|
|
|
Most front-end applications need to communicate with a server over the HTTP protocol, to download or upload data and access other back-end services.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
You can run the <live-example name="http"></live-example> that accompanies this guide.
|
|
|
|
The sample app does not require a data server.
|
|
It relies on the [Angular *in-memory-web-api*](https://github.com/angular/angular/tree/main/packages/misc/angular-in-memory-web-api), which replaces the *HttpClient* module's `HttpBackend`.
|
|
The replacement service simulates the behavior of a REST-like backend.
|
|
|
|
Look at the `bootstrapApplication()` method in `main.ts` to see how it is configured.
|
|
|
|
</div>
|
|
|
|
## Setup for server communication
|
|
|
|
Before you can use `HttpClient`, you need to provide the Angular `HttpClientModule` so that it is available for [dependency injection](guide/dependency-injection) into the classes that need it.
|
|
|
|
Most developers provide the `HttpClientModule` when initializing the app with `bootstrapApplication` in `main.ts` using `ApplicationConfig` exported by `app.config.ts` as shown in this example:
|
|
|
|
<code-example header="main.ts (excerpt)" path="http/src/main.ts" region="sketch"></code-example>
|
|
|
|
<code-example header="app.config.ts (excerpt)" path="http/src/app/app.config.ts" region="sketch"></code-example>
|
|
|
|
You can then inject the `HttpClient` service as a dependency of an application class, as shown in the following `ConfigService` example.
|
|
|
|
<code-example header="app/config/config.service.ts (excerpt)" path="http/src/app/config/config.service.ts" region="proto"></code-example>
|
|
|
|
## Requesting data from a server
|
|
|
|
Use the [`HttpClient.get()`](api/common/http/HttpClient#get) method to fetch data from a server.
|
|
The asynchronous method sends an HTTP request, and returns an Observable that emits the requested data when the response is received.
|
|
The return type varies based on the `observe` and `responseType` values that you pass to the call.
|
|
|
|
The `get()` method takes two arguments; the endpoint URL from which to fetch, and an *options* object that is used to configure the request.
|
|
|
|
<code-example format="typescript" language="typescript">
|
|
|
|
options: {
|
|
headers?: HttpHeaders | {[header: string]: string | string[]},
|
|
observe?: 'body' | 'events' | 'response',
|
|
params?: HttpParams|{[param: string]: string | number | boolean | ReadonlyArray<string | number | boolean>},
|
|
reportProgress?: boolean,
|
|
responseType?: 'arraybuffer'|'blob'|'json'|'text',
|
|
withCredentials?: boolean,
|
|
}
|
|
|
|
</code-example>
|
|
|
|
Important options include the *observe* and *responseType* properties.
|
|
|
|
* The *observe* option specifies how much of the response to return
|
|
* The *responseType* option specifies the format in which to return data
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
Use the `options` object to configure various other aspects of an outgoing request.
|
|
In adding headers, for example, the service set the default headers using the `headers` option property.
|
|
|
|
Use the `params` property to configure a request with HTTP URL parameters, and the `reportProgress` option to listen for progress events when transferring large amounts of data.
|
|
|
|
</div>
|
|
|
|
Applications often request JSON data from a server.
|
|
In the `ConfigService` example, the app needs a configuration file on the server, `config.json`, that specifies resource URLs.
|
|
|
|
<code-example header="assets/config.json" path="http/src/assets/config.json"></code-example>
|
|
|
|
To fetch this kind of data, the `get()` call needs the following options: `{observe: 'body', responseType: 'json'}`.
|
|
These are the default values for those options, so the following examples do not pass the options object.
|
|
Later sections show some of the additional option possibilities.
|
|
|
|
<a id="config-service"></a>
|
|
|
|
The example conforms to the best practices for creating scalable solutions by defining a re-usable [injectable service](guide/glossary#service "service definition") to perform the data-handling functionality.
|
|
In addition to fetching data, the service can post-process the data, add error handling, and add retry logic.
|
|
|
|
The `ConfigService` fetches this file using the `HttpClient.get()` method.
|
|
|
|
<code-example header="app/config/config.service.ts (getConfig v.1)" path="http/src/app/config/config.service.ts" region="getConfig_1"></code-example>
|
|
|
|
The `ConfigComponent` injects the `ConfigService` and calls the `getConfig` service method.
|
|
|
|
Because the service method returns an `Observable` of configuration data, the component *subscribes* to the method's return value.
|
|
The subscription callback performs minimal post-processing.
|
|
It copies the data fields into the component's `config` object, which is data-bound in the component template for display.
|
|
|
|
<code-example header="app/config/config.component.ts (showConfig v.1)" path="http/src/app/config/config.component.ts" region="v1"></code-example>
|
|
|
|
<a id="always-subscribe"></a>
|
|
|
|
### Starting the request
|
|
|
|
For all `HttpClient` methods, the method doesn't begin its HTTP request until you call `subscribe()` on the observable the method returns.
|
|
|
|
This is true for *all* `HttpClient` *methods*.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
You should always unsubscribe from an observable when a component is destroyed.
|
|
|
|
</div>
|
|
|
|
All observables returned from `HttpClient` methods are *cold* by design.
|
|
Execution of the HTTP request is *deferred*, letting you extend the observable with additional operations such as `tap` and `catchError` before anything actually happens.
|
|
|
|
Calling `subscribe()` triggers execution of the observable and causes `HttpClient` to compose and send the HTTP request to the server.
|
|
|
|
Think of these observables as *blueprints* for actual HTTP requests.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
In fact, each `subscribe()` initiates a separate, independent execution of the observable.
|
|
Subscribing twice results in two HTTP requests.
|
|
|
|
<code-example format="javascript" language="javascript">
|
|
|
|
const req = http.get<Heroes>('/api/heroes');
|
|
// 0 requests made - .subscribe() not called.
|
|
req.subscribe();
|
|
// 1 request made.
|
|
req.subscribe();
|
|
// 2 requests made.
|
|
|
|
</code-example>
|
|
|
|
</div>
|
|
|
|
<a id="typed-response"></a>
|
|
|
|
### Requesting a typed response
|
|
|
|
Structure your `HttpClient` request to declare the type of the response object, to make consuming the output easier and more obvious.
|
|
Specifying the response type acts as a type assertion at compile time.
|
|
|
|
<div class="alert is-important">
|
|
|
|
Specifying the response type is a declaration to TypeScript that it should treat your response as being of the given type.
|
|
This is a build-time check and doesn't guarantee that the server actually responds with an object of this type.
|
|
It is up to the server to ensure that the type specified by the server API is returned.
|
|
|
|
</div>
|
|
|
|
To specify the response object type, first define an interface with the required properties.
|
|
Use an interface rather than a class, because the response is a plain object that cannot be automatically converted to an instance of a class.
|
|
|
|
<code-example path="http/src/app/config/config.service.ts" region="config-interface"></code-example>
|
|
|
|
Next, specify that interface as the `HttpClient.get()` call's type parameter in the service.
|
|
|
|
<code-example header="app/config/config.service.ts (getConfig v.2)" path="http/src/app/config/config.service.ts" region="getConfig_2"></code-example>
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
When you pass an interface as a type parameter to the `HttpClient.get()` method, use the [RxJS `map` operator](guide/rx-library#operators) to transform the response data as needed by the UI.
|
|
You can then pass the transformed data to the [async pipe](api/common/AsyncPipe).
|
|
|
|
</div>
|
|
|
|
The callback in the updated component method receives a typed data object, which is easier and safer to consume:
|
|
|
|
<code-example header="app/config/config.component.ts (showConfig v.2)" path="http/src/app/config/config.component.ts" region="v2"></code-example>
|
|
|
|
To access properties that are defined in an interface, you must explicitly convert the plain object you get from the JSON to the required response type.
|
|
For example, the following `subscribe` callback receives `data` as an Object, and then type-casts it in order to access the properties.
|
|
|
|
<code-example format="typescript" language="typescript">
|
|
|
|
.subscribe(data => this.config = {
|
|
heroesUrl: (data as any).heroesUrl,
|
|
textfile: (data as any).textfile,
|
|
});
|
|
|
|
</code-example>
|
|
|
|
<a id="string-union-types"></a>
|
|
|
|
<div class="callout is-important">
|
|
|
|
<header><code>observe</code> and <code>response</code> types</header>
|
|
|
|
The types of the `observe` and `response` options are *string unions*, rather than plain strings.
|
|
|
|
<code-example format="typescript" language="typescript">
|
|
|
|
options: {
|
|
…
|
|
observe?: 'body' | 'events' | 'response',
|
|
…
|
|
responseType?: 'arraybuffer'|'blob'|'json'|'text',
|
|
…
|
|
}
|
|
|
|
</code-example>
|
|
|
|
This can cause confusion.
|
|
For example:
|
|
|
|
<code-example format="typescript" language="typescript">
|
|
|
|
// this works
|
|
client.get('/foo', {responseType: 'text'})
|
|
|
|
// but this does NOT work
|
|
const options = {
|
|
responseType: 'text',
|
|
};
|
|
client.get('/foo', options)
|
|
|
|
</code-example>
|
|
|
|
In the second case, TypeScript infers the type of `options` to be `{responseType: string}`.
|
|
The type is too wide to pass to `HttpClient.get` which is expecting the type of `responseType` to be one of the *specific* strings.
|
|
`HttpClient` is typed explicitly this way so that the compiler can report the correct return type based on the options you provided.
|
|
|
|
Use `as const` to let TypeScript know that you really do mean to use a constant string type:
|
|
|
|
<code-example format="typescript" language="typescript">
|
|
|
|
const options = {
|
|
responseType: 'text' as const,
|
|
};
|
|
client.get('/foo', options);
|
|
|
|
</code-example>
|
|
|
|
</div>
|
|
|
|
### Reading the full response
|
|
|
|
In the previous example, the call to `HttpClient.get()` did not specify any options.
|
|
By default, it returned the JSON data contained in the response body.
|
|
|
|
You might need more information about the transaction than is contained in the response body.
|
|
Sometimes servers return special headers or status codes to indicate certain conditions that are important to the application workflow.
|
|
|
|
Tell `HttpClient` that you want the full response with the `observe` option of the `get()` method:
|
|
|
|
<code-example path="http/src/app/config/config.service.ts" region="getConfigResponse"></code-example>
|
|
|
|
Now `HttpClient.get()` returns an `Observable` of type `HttpResponse` rather than just the JSON data contained in the body.
|
|
|
|
The component's `showConfigResponse()` method displays the response headers as well as the configuration:
|
|
|
|
<code-example header="app/config/config.component.ts (showConfigResponse)" path="http/src/app/config/config.component.ts" region="showConfigResponse"></code-example>
|
|
|
|
As you can see, the response object has a `body` property of the correct type.
|
|
|
|
@reviewed 2023-08-16
|