Angularの基礎(API連係)
要点
Angularの学習として、今後アプリケーションを作っていくに当てって、4つのポイントで要点をまとめました。
- 基本構成
- ルーティングによる画面遷移
- ルーティングを使わない画面遷移
- API連係
この記事では4について記録しておきたいと思います。
前提
以前に紹介したDockerの環境で「sample03」プロジェクトを新たに作成します。
連係するAPIについては、AWSのLambdaとAPI Gatewayでテスト用のものを用意します。
APIの用意
AWS Lambda
コンソールからAWS Lambdaに遷移して、「関数の作成」を押下します。
オプションで「一から作成」を選択して、関数名を「myTest」、ランタイムは「Node.js 20.x」、アーキテクチャは「x86_64」、アクセス権限はデフォルトのままで「関数の作成」ボタンを押下します。
「myTest」関数ができたら、「コード」タブで以下のコードを入力します。
export const handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: {
users: [
{username: 'test1', firstname: '太郎', lastname: '東北', email: 'test1@example.com'},
{username: 'test2', firstname: '次郎', lastname: '宮城', email: 'test2@example.com'},
{username: 'test3', firstname: '花子', lastname: '仙台', email: 'test3@example.com'},
]
},
};
return response;
};
Deployしたら、テストで正常に動作することを確認します。
API Gateway
APIを作成
コンソールからAPI Gatewayに遷移して、「REST API」を選択して「構築」ボタンを押下します。
「新しいAPI」でAPI名は「myTestAPI」、APIエンドポイントタイプは「リージョン」として「APIを作成」ボタンを押下します。
メソッドを作成
「メソッドを作成」を押下し、メソッドタイプは「GET」、統合タイプは「Lambda関数」、Lambda関数は先ほど作成した「myTest」関数を選択します。
他はデフォルトのままで「メソッドを作成」ボタンを押下します。
CORSを設定
「CORSを有効にする」ボタンを押下して、設定画面に遷移します。
ゲートウェイのレスポンスは4xx、5xx両方を対象。
許可するメソッドは「GET」。
今回は一時的なテスト用なので、originは全て許容します。
「保存」ボタンを押下して、設定を確定します。
※不正アクセスなどの危険性があるので、使い終わったらAPIを削除しましょう。
APIをデプロイ
「APIをデプロイ」ボタンを押下して、設定ウィンドウを表示します。
ステージは「新しいステージ」を選択して、ステージ名は「test」とします。
「デプロイ」ボタンを押下して、デプロイします。
APIをテスト
コンソールにAPIのエンドポイントが表示されているので、それをコピーして、ブラウザで実行してみます。
Angularのコーディング
モデルクラスを作成
データを格納するモデルクラスを作成
作成先として、/src/app/model のフォルダを作り、その下にuserクラスを展開。
ターミナルで以下コマンドを実行します。
ng generate class model/user --type=model
/src/app/model/user.model.ts ファイルが作成されます。
user.model.tsを編集
/src/app/mode/user.model.ts を以下のように編集。
export class User {
constructor(public username: string, public firstname: string, public lastname: string, public email: string) {}
}
コンストラクタで変数定義をします。
データを表示する画面を作成
user-listコンポーネントを作成
ターミナルで以下コマンドを実行
ng generate component user-list
/src/app/user-listのコンポーネント一式が作成されます。
user-list.component.tsを編集
/src/app/user-list/user-list.component.tsを以下のように編集。
import { Component } from '@angular/core';
import { User } from '../model/user.model';
import { NgFor } from '@angular/common';
@Component({
selector: 'app-user-list',
standalone: true,
imports: [NgFor],
templateUrl: './user-list.component.html',
styleUrl: './user-list.component.css'
})
export class UserListComponent {
}
UserモデルクラスとNgForディレクティブをインポートする。
(中間確認用)データをオンコード
APIと連係する前に、内部処理の理解のために、データをオンコードします。
/src/app/user-list/user-list.component.ts を以下のように編集。
import { Component } from '@angular/core';
import { User } from '../model/user.model';
import { NgFor } from '@angular/common';
@Component({
selector: 'app-user-list',
standalone: true,
imports: [NgFor],
templateUrl: './user-list.component.html',
styleUrl: './user-list.component.css'
})
export class UserListComponent {
users: User[] = [];
ngOnInit() {
let user1 = new User('user1', '一郎', '佐藤', 'sato@example.com');
let user2 = new User('user2', '二郎', '鈴木', 'suzuki@example.com');
this.users.push(user1);
this.users.push(user2);
}
}
users配列を用意して、初期処理(ライフサイクルフック)で固定データをセットしています。
user-list.component.htmlを編集
/src/app/user-list/user-list.component.html を以下のように編集。
<h3>APIの接続結果</h3>
<div>一覧表示</div>
<table>
<thead>
<tr>
<th>username</th>
<th>firstname</th>
<th>lastname</th>
<th>email</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of users">
<td>{{ user.username }}</td>
<td>{{ user.firstname }}</td>
<td>{{ user.lastname }}</td>
<td>{{ user.email }}</td>
</tr>
</tbody>
</table>
NgForディレクティブを使って、データ件数分をループさせてます。
app.component.tsを編集
/src/app/app.component.ts を以下のように編集。
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { UserListComponent } from './user-list/user-list.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, UserListComponent],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent {
title = 'sample03';
}
user-listコンポーネントをインポート。
app.component.htmlを編集
/src/app/app.component.html を以下のように編集。
<h1>API連係テスト</h1>
<app-user-list></app-user-list>
user-list.component.html を画面表示。
結果確認
「ng serve --host 0.0.0.0」をコマンド実行して、ブラウザで確認。
固定データが一覧で表示されました。
API連係を実装
API連係用のサービスクラスを作成
作成先として、/src/app/api のフォルダを作り、その下にuserクラスを展開。
ターミナルで以下コマンドを実行します。
ng generate service api/users
/src/app/api/users.service.ts ファイルが作成されます。
users.service.tsを編集
/src/app/api/users.service.tsを以下のように編集。
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { User } from '../model/user.model';
@Injectable({
providedIn: 'root'
})
export class UsersService {
users: User[] = [];
constructor(private httpCient: HttpClient) {}
getUsers = ():Observable<User[]> => {
return this.httpCient.get<User[]>('https://tx4y6a1yj8.execute-api.ap-northeast-1.amazonaws.com/test');
}
}
API連係するために HttpClient をインポート。
非同期処理のために Observable をインポート。(Promiseで処理することもできるらしいが、今回はObservableで実施)
コンストラクタで、HttpClientのインスタンスを生成して、getUsersメソッド内でAPIを実行。
URLは、前述で作成したLambda+API Gatewayのエンドポイント。
(要注意)HttpClientクラスをインスタンスかしたときにアベンドする
ここで1点ハマりどころがありましたので、要注意です。
実際にうごかく断面で判明したのですが、HttpClientクラスをインスタンス化するところでアベンドしてしまいます。
どうやらAngular17ではapp.config.tsで以下の対処が必要ということがわかりました。
/src/app/app.config.ts を以下のように編集。
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideHttpClient } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes), provideHttpClient()]
};
providerHttpClientをインポートして、providersに追加します。
user-list.component.tsを編集
前述で中間確認用にオンコードでデータを記述していたところを、API連係に書き換えます。
/src/app/user-list/user-list.component.ts を以下のように編集。
import { Component } from '@angular/core';
import { User } from '../model/user.model';
import { NgFor } from '@angular/common';
import { UsersService } from '../api/users.service';
@Component({
selector: 'app-user-list',
standalone: true,
imports: [NgFor],
templateUrl: './user-list.component.html',
styleUrl: './user-list.component.css'
})
export class UserListComponent {
users: User[] = [];
constructor(private service: UsersService) {}
ngOnInit() {
this.service.getUsers().subscribe((res:any) => {
this.users = res.body.users;
})
}
}
UsersServiceをインポートして、コンストラクタでインスタンス化する。
初期処理(ライフサイクルフック)でAPI連係して、その結果をセットしています。
結果を確認
「ng serve --host 0.0.0.0」で実行し、ブラウザで見てみます。
しっかりとAPIの結果で画面が表示されていることが確認できました。
最後に
今回はObservableという方法で非同期処理を行いましたが、ReactのAxiosなんかだとPromiseで非同期をするのがスタンダードだと思います。
AngularでもPromiseでの方法もあるようなので、そこは今後の学習とします。
この記事までで、全4回に分けて、Angularの基本をまとめてみました。
実際のフロントエンド開発で、より深いところまで理解しながら進めていきたいと思います。