はじめに
本稿はシステムアイ Advent Calendar 2022の記事となります。
Angular(アンギュラー)はGoogle社によって開発されているTypeScriptベースのフロントエンドフレームワークです。React、Vue.jsと並んで人気があるフレークワークの一つとなっています。(厳密にはReact、Vue.jsはフレームワークではなくライブラリです)
また、Angularの特徴としてフルスタック(全部入り)のフレームワークとなり、標準の機能だけでアプリケーションが作ることができます。
今回はそんなAngularの知っておきたい基本の3つの機能をお送りします。
Service
Angularのサービス(Service)という機能があります。サービスを使うとコンポーネントからロジック部分を分離する(別ファイルに分ける)ことができます。
例えば、サーバーからのデータ取得、入力チェック、ログ出力などをサービスに記述することで、コンポーネントから左記ロジックを切り離せるため、サービス、コンポーネントの再利用性があがります。
また、サービスをシングルトン(単一インスタンス)にし、アプリケーションにひとつだけ存在させることができます。サービスを定義するInjectableデコレータにprovidedIn: 'root'
を書くだけでシングルトンにでき、アプリケーション内で利用することができます。(※)
Angular CLIが導入されている環境であれば、下記コマンドを実行するだけで簡単にシングルトンのサービスが作成できます。
ng generate service user
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class UserService {
}
※Angularが6.0未満の場合は、providedIn: 'root'
ではなく、AppModuleにサービスを定義する必要があります。
@NgModule({
...
providers: [UserService],
...
})
HttpInterceptor
HTTPリクエスト/レスポンスに共通の前処理を挟み込むことができます。
例えばリクエストヘッダーに認証トークンを設定したり、レスポンスの結果を共通的に扱いたい場合に本機能を利用します。
import { Injectable } from '@angular/core';
import {
HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse
} from '@angular/common/http';
import { Observable,tap } from 'rxjs';
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// sesion storageに保存されているトークンを取り出す
const token = sessionStorage.getItem('token');
// 全てのリクエストのAuthorizationヘッダーにトークンをセット
const newRequest = request.clone({
headers: request.headers.set(
'Authorization', `Bearer ${token}`
)
});
return next.handle(newRequest);
}
}
レスポンスヘッダーからトークンを取り出す場合はreturn next.handle(newRequest);
を下記のように書き換えます。
...
return next.handle(newRequest).pipe(
tap((res) =>{
if(res instanceof HttpResponse){
const token = res.headers.get('token')
if(token){
sessionStorage.setItem('token',token)
}
}
})
);
...
Guard
Angularのガード(Guard)を使えば、ルーティング前後に処理を挟むことができます。
例えば、次のページへ遷移する際に権限のチェックをする際などにシーンに利用します。
こちらもAngular CLIが導入されている環境であれば、下記コマンドを実行するだけで簡単にガードを作成できます。
ng generate guard auth
? Which interfaces would you like to implement? CanActivate
CREATE src/app/auth.guard.spec.ts (331 bytes)
CREATE src/app/auth.guard.ts (457 bytes)
PS C:\Users\systemi\work\angular\my-app>
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return true;
}
}
canActivateのリターンがtrueの場合は通常通りページに遷移、falseの場合は遷移不可にできます。
下記はガードを書き換え、session storageにトークンがない場合はログインページに転送するようにしています。
...
constructor(
private router: Router
) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
if (!sessionStorage.getItem('token')) {
this.router.navigate(['login']);
return false;
}
return true;
}
ガードしたいルートに対してガードを記述します。
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './login/login.component'
import { AuthGuard } from './auth.guard';
const routes: Routes = [
{ path: 'login', component: LoginComponent , canActivate: [AuthGuard] }
];
@NgModule({
imports: [CommonModule,RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule { }
まとめ
Angularで知っておきたい3つの機能をご紹介しました。
そのほかにもディレクティブ、パイプ、バリデーション、遅延ロードなどたくさんの機能を標準で備えたAngularにぜひ触れてみてください。
Angular
https://angular.jp/