HTTP リクエストを行う
HttpClient には、データの読み込みとサーバーへの変更の適用に使用されるさまざまなHTTP動詞に対応するメソッドがあります。各メソッドはRxJS Observable を返し、これはサブスクライブされるとリクエストを送信し、サーバーが応答すると結果を発行します。
Note: HttpClient によって作成された Observable は、何度でもサブスクライブでき、各サブスクライブごとに新しいバックエンドリクエストが行われます。
リクエストメソッドに渡されるオプションオブジェクトを通じて、リクエストのさまざまなプロパティと返されるレスポンスタイプを調整できます。
JSON データの取得
バックエンドからデータを取得するには、多くの場合、HttpClient.get() メソッドを使用してGETリクエストを行う必要があります。このメソッドは、2つの引数を取ります。1つ目は、フェッチする文字列のエンドポイントURL、2つ目はリクエストを構成するためのオプションオブジェクトです(省略可能)。
たとえば、HttpClient.get() メソッドを使用して、仮説上のAPIから構成データを取得するには、次のようになります。
http.get<Config>('/api/config').subscribe(config => { // 構成を処理します。});
サーバーによって返されるデータが Config 型であることを指定するジェネリック型引数に注意してください。この引数は省略可能であり、省略すると、返されるデータは any 型になります。
Tip: データの形が不明な場合は、any 型よりも安全な代替手段として、unknown 型をレスポンス型として使用します。
CTIRICAL: リクエストメソッドのジェネリック型は、サーバーによって返されるデータに関するアサーションです。HttpClient は、実際の戻り値データがこの型と一致することを検証しません。
他のタイプのデータの取得
デフォルトでは、HttpClient はサーバーがJSONデータを返すことを想定しています。JSON以外のAPIと対話する場合、HttpClient にリクエストを行うときに期待されるレスポンス型と返す型を伝えることができます。これは、responseType オプションを使用して行います。
responseType 値 |
返されるレスポンス型 |
|---|---|
'json' (デフォルト) |
指定されたジェネリック型の JSON データ |
'text' |
文字列データ |
'arraybuffer' |
応答バイトの生のデータを格納した ArrayBuffer |
'blob' |
Blob インスタンス |
たとえば、HttpClient に .jpeg イメージの生のバイトを ArrayBuffer にダウンロードするように依頼できます。
http.get('/images/dog.jpg', {responseType: 'arraybuffer'}).subscribe(buffer => { console.log('画像は ' + buffer.byteLength + ' バイトです');});
responseType のリテラル値
responseType の値は、HttpClient によって返される型に影響を与えるため、string 型ではなく、リテラル型である必要があります。
これは、リクエストメソッドに渡されるオプションオブジェクトがリテラルオブジェクトの場合に自動的に発生しますが、リクエストオプションを変数やヘルパーメソッドに抽出している場合は、responseType: 'text' as const のように明示的にリテラルとして指定する必要があるかもしれません。
サーバーの状態を変更する
変更を伴うサーバーAPIは多くの場合、新しい状態または行うべき変更を指定したリクエストボディを使用してPOSTリクエストを行う必要があります。
HttpClient.post() メソッドは get() と同様に動作し、オプションの前に body 引数を追加で受け取ります。
http.post<Config>('/api/config', newConfig).subscribe(config => { console.log('更新された構成:', config);});
さまざまなタイプの値をリクエストの body として提供でき、HttpClient はそれに応じてシリアル化します。
body 型 |
シリアル化されるもの |
|---|---|
| 文字列 | プレーンテキスト |
| 数値、ブール値、配列、またはプレーンオブジェクト | JSON |
ArrayBuffer |
バッファーからの生データ |
Blob |
Blob のコンテンツタイプを使用した生データ |
FormData |
multipart/form-data エンコードされたデータ |
HttpParams または URLSearchParams |
application/x-www-form-urlencoded 形式の文字列 |
IMPORTANT: 変更リクエスト Observable を .subscribe() することを忘れないでください。そうしないと、リクエストは実際に発行されません。
URL パラメータの設定
リクエストURLに含めるべきリクエストパラメータは、params オプションを使用して指定します。
オブジェクトリテラルを渡すことは、URLパラメータを構成するための最も簡単な方法です。
http.get('/api/config', { params: {filter: 'all'},}).subscribe(config => { // ...});
あるいは、パラメータの構築やシリアル化をより細かく制御する必要がある場合は、HttpParams のインスタンスを渡します。
IMPORTANT: HttpParams のインスタンスは変更不可能であり、直接変更できません。代わりに、append() などの変更メソッドは、変更が適用された新しい HttpParams のインスタンスを返します。
const baseParams = new HttpParams().set('filter', 'all');http.get('/api/config', { params: baseParams.set('details', 'enabled'),}).subscribe(config => { // ...});
HttpParams を、HttpClient がパラメータをURLにエンコードする方法を決定するカスタム HttpParameterCodec でインスタンス化できます。
リクエストヘッダーの設定
リクエストに含めるべきリクエストヘッダーは、headers オプションを使用して指定します。
オブジェクトリテラルを渡すことは、リクエストヘッダーを構成するための最も簡単な方法です。
http.get('/api/config', { headers: { 'X-Debug-Level': 'verbose', }}).subscribe(config => { // ...});
あるいは、ヘッダーの構築をより細かく制御する必要がある場合は、HttpHeaders のインスタンスを渡します。
IMPORTANT: HttpHeaders のインスタンスは変更不可能であり、直接変更できません。代わりに、append() などの変更メソッドは、変更が適用された新しい HttpHeaders のインスタンスを返します。
const baseHeaders = new HttpHeaders().set('X-Debug-Level', 'minimal');http.get<Config>('/api/config', { headers: baseHeaders.set('X-Debug-Level', 'verbose'),}).subscribe(config => { // ...});
サーバーレスポンスイベントとの対話
便宜上、HttpClient はデフォルトでサーバーによって返されるデータ(レスポンスボディ)の Observable を返します。場合によっては、特定のレスポンスヘッダーを取得するなど、実際のレスポンスを調べる必要がある場合もあります。
レスポンス全体にアクセスするには、observe オプションを 'response' に設定します。
http.get<Config>('/api/config', {observe: 'response'}).subscribe(res => { console.log('レスポンスステータス:', res.status); console.log('ボディ:', res.body);});
observe のリテラル値
observe の値は、HttpClient によって返される型に影響を与えるため、string 型ではなく、リテラル型である必要があります。
これは、リクエストメソッドに渡されるオプションオブジェクトがリテラルオブジェクトの場合に自動的に発生しますが、リクエストオプションを変数やヘルパーメソッドに抽出している場合は、observe: 'response' as const のように明示的にリテラルとして指定する必要があるかもしれません。
生の進捗イベントを受信する
HttpClient は、レスポンスボディとレスポンスオブジェクトに加えて、リクエストライフサイクルの特定の時点に対応する生のイベントのストリームを返せます。これらのイベントには、リクエストが送信されたとき、レスポンスヘッダーが返されたとき、ボディが完了したときなどが含まれます。これらのイベントには、大きなリクエストボディとレスポンスボディのアップロードとダウンロードの状態を報告する進捗イベントも含まれる場合があります。
進捗イベントは、デフォルトでは無効になっています(パフォーマンス上のコストがかかるため)が、reportProgress オプションを使用して有効にできます。
Note: HttpClient のオプションの fetch 実装は、アップロードの進捗イベントを報告しません。
イベントストリームを観察するには、observe オプションを 'events' に設定します。
http.post('/api/upload', myData, { reportProgress: true, observe: 'events',}).subscribe(event => { switch (event.type) { case HttpEventType.UploadProgress: console.log('Uploaded ' + event.loaded + ' out of ' + event.total + ' bytes'); break; case HttpEventType.Response: console.log('Finished uploading!'); break; }});
observe のリテラル値
observe の値は、HttpClient によって返される型に影響を与えるため、string 型ではなく、リテラル型である必要があります。
これは、リクエストメソッドに渡されるオプションオブジェクトがリテラルオブジェクトの場合に自動的に発生しますが、リクエストオプションを変数やヘルパーメソッドに抽出している場合は、observe: 'events' as const のように明示的にリテラルとして指定する必要があるかもしれません。
イベントストリームで報告される各 HttpEvent には、イベントを表す type があります。
type 値 |
イベントの意味 |
|---|---|
HttpEventType.Sent |
リクエストがサーバーに送信されました |
HttpEventType.UploadProgress |
リクエストボディのアップロードの進捗状況を報告する HttpUploadProgressEvent |
HttpEventType.ResponseHeader |
レスポンスのヘッダーが受信されました。ステータスとヘッダーが含まれています |
HttpEventType.DownloadProgress |
レスポンスボディのダウンロードの進捗状況を報告する HttpDownloadProgressEvent |
HttpEventType.Response |
レスポンス全体が受信されました。レスポンスボディが含まれています |
HttpEventType.User |
Http インターセプターからのカスタムイベント |
リクエスト失敗の処理
HTTPリクエストは、次の2つの方法で失敗する可能性があります。
- ネットワークエラーまたは接続エラーにより、リクエストがバックエンドサーバーに到達できない場合があります。
- バックエンドがリクエストを受け取りますが、処理に失敗し、エラーレスポンスを返す場合があります。
HttpClient は、HttpErrorResponse に両方の種類のエラーを捕捉し、Observable のエラーチャネルを通じて返します。ネットワークエラーの status コードは 0 で、error は ProgressEvent のインスタンスです。バックエンドエラーの status コードは、バックエンドによって返された失敗したコードであり、error はエラーレスポンスです。レスポンスを調べて、エラーの原因とエラーを処理するための適切なアクションを特定します。
RxJS ライブラリ は、エラー処理に役立つ演算子をいくつか提供しています。
catchError 演算子を使用して、エラーレスポンスをUI用の値に変換できます。この値は、UIにエラーページまたは値を表示し、必要に応じてエラーの原因を捕捉します。
ネットワークの中断など、一時的なエラーにより、予期せずリクエストが失敗することがあります。リクエストを再試行するだけで成功する場合があります。RxJSは、特定の条件下で失敗した Observable に自動的に再購読する、複数の再試行演算子を提供しています。たとえば、retry() 演算子は、指定された回数だけ自動的に再サブスクライブを試みます。
Http Observable
HttpClient の各リクエストメソッドは、要求されたレスポンス型の Observable を構築して返します。これらの Observable の仕組みを理解することは、HttpClient を使用する場合に重要です。
HttpClient は、RxJSが「コールド」と呼ぶ Observable を生成します。つまり、Observable がサブスクライブされるまでは、実際のリクエストは行われません。リクエストが実際にサーバーに送信されるのは、そのときだけです。同じ Observable を複数回購読すると、複数のバックエンドリクエストがトリガーされます。各サブスクライブは独立しています。
TIP: HttpClient の Observable は、実際のリクエストのブループリントと考えることができます。
いったんサブスクライブされると、アン購読すると、進行中のリクエストが中止されます。これは、Observable が async パイプを使用してサブスクライブされている場合に非常に便利です。ユーザーが現在のページから移動すると、リクエストが自動的にキャンセルされます。さらに、Observable を switchMap などのRxJSコンビネータと使用する場合、このキャンセルによって、古いリクエストがすべてクリーンアップされます。
レスポンスが返されると、HttpClient からの Observable は通常完了します(ただし、インターセプターがこれに影響を与える可能性があります)。
自動完了のため、HttpClient のサブスクライブがクリーンアップされなくても、通常はメモリリークのリスクはありません。ただし、他の非同期操作と同様に、サブスクライブを使用しているコンポーネントが破棄されたときにサブスクライブをクリーンアップすることを強くお勧めします。そうしないと、サブスクライブコールバックが実行され、破棄されたコンポーネントと対話するときにエラーが発生する可能性があります。
TIP: async パイプまたは toSignal 演算子を使用して Observable に購読すると、サブスクライブが適切に破棄されます。
ベストプラクティス
HttpClient はコンポーネントから直接注入して使用できますが、一般的にはデータアクセスロジックを分離してカプセル化する、再利用できる注入可能なサービスを作成することをお勧めします。たとえば、この UserService は、IDでユーザーのデータをリクエストするロジックをカプセル化しています。
@Injectable({providedIn: 'root'})export class UserService { constructor(private http: HttpClient) {} getUser(id: string): Observable<User> { return this.http.get<User>(`/api/user/${id}`); }}
コンポーネント内で、@if を async パイプと組み合わせて、データの読み込みが完了した後にのみ、データのUIをレンダリングできます。
import { AsyncPipe } from '@angular/common';@Component({ standalone: true, imports: [AsyncPipe], template: ` @if (user$ | async; as user) { <p>名前: {{ user.name }}</p> <p>経歴: {{ user.biography }}</p> } `,})export class UserProfileComponent { @Input() userId!: string; user$!: Observable<User>; constructor(private userService: UserService) {} ngOnInit(): void { this.user$ = userService.getUser(this.userId); }}