mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
221 lines
9.1 KiB
Markdown
221 lines
9.1 KiB
Markdown
# HTTP: Request 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-02-27
|