はじめまして。Advent Calendar初参加になります!AWS Amplifyは一年前くらいから触り始めてその便利さから愛用しているので、今回はその知見をアウトプットできたらと思います。
目黒にあるAWS Loft TokyoでAWS Amplifyに出会った
1年ほど前、東京都の目黒駅徒歩1分の場所に「AWS Loft Tokyo」なる施設がオープンしました。
スタートアップとデベロッパーのための「挑戦をカタチにする場所」というコンセプトです。
今回のAWS Amplify Advent Calendarを作ったのもスタートアップソリューションアーキテクトの塚田さん( @akitsukada )ですね。
Loftにはオープンから足を運んでおり、コワーキング利用終了後に毎週のように開催される技術系イベントに参加していました。
参加したイベントの一つが「AWS Amplify Blackbelt公開収録 & AppSync入門」です。
Ionic(アイオニック)とは
Ionicとは、HTML / CSS / JSの技術でモバイルアプリを作るためのUIフレームワークと言ったところでしょうか。iOS / AndroidのUIに極限まで近づけたUIコンポーネントが提供されており、美しいUIのアプリを素早く構築することができます。
CordovaやCapacitorを使うことで、Ionicで作ったアプリをiOS / Android用アプリとしてビルドしてApp Store / Google Playに並べることができます。
僕は3年ほどスタートアップで一人エンジニアをやっていたので、iOS / Androidアプリを一気に構築できるIonicがとても気に入っていました。
そこにAWS Amplifyが加わることで、フロントエンドからバックエンドまで一人で作ることができるくらいスピードを上げることができます。
今回はそんなIonicで作ったアプリにAWS Amplifyを組み込んで使うための手順をまとめようと思います。
動作確認環境
- macOS Catalina 10.15
- VS Code
- node.js v12.7.0
- @angular/core 8.1.2
- @ionic/angular 4.7.1
- aws-amplify 1.2.4
- aws-amplify-angular 4.7.1
- @amplify/cli 3.17.0
Ionicプロジェクトを新しく作成する
まずはIonic CLIを利用してプロジェクトを生成します。
npx
を使うことでIonic CLIをグローバルインストールしていなくてもコマンドを利用できます。
# CLIでプロジェクトを作成開始
$ npx ionic start
# プロジェクト名を指定
? Project name: AmplifyIonicChat
# JSフレームワークを選択:今回はAngularを利用
? Framework: Angular
# テンプレートを選択
? Starter template: blank
# ディレクトリに移動
$ cd AmplifyIonicChat
この時点でのディレクトリ構造は次のようになります。
基本的にはAngular CLIで生成されるディレクトリと同じです。
$ tree -I node_modules
.
├── angular.json
├── browserslist
├── e2e
│ ├── protractor.conf.js
│ ├── src
│ │ ├── app.e2e-spec.ts
│ │ └── app.po.ts
│ └── tsconfig.json
├── ionic.config.json
├── karma.conf.js
├── package-lock.json
├── package.json
├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.html
│ │ ├── app.component.scss
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ └── home
│ │ ├── home.module.ts
│ │ ├── home.page.html
│ │ ├── home.page.scss
│ │ ├── home.page.spec.ts
│ │ └── home.page.ts
│ ├── assets
│ │ ├── icon
│ │ │ └── favicon.png
│ │ └── shapes.svg
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── global.scss
│ ├── index.html
│ ├── main.ts
│ ├── polyfills.ts
│ ├── test.ts
│ ├── theme
│ │ └── variables.scss
│ └── zone-flags.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
└── tslint.json
これだけでもう動作確認ができるので、AWS Amplify JavaScript Frameworkを入れる前に一旦動かしてみます。
# 開発サーバーを起動
$ npx ionic serve
自動でデフォルトのブラウザが開き、アプリケーションが表示されます。
これだけでiOS端末ではiOSのスタイルが、Android端末ではマテリアルデザインのスタイルが適用されたアプリケーションの雛形が出来上がります。
AWS Amplify JavaScript Frameworkをインストール
Ionicアプリケーションの準備が整ったので、ここから本題のAWS Amplifyを導入します。
公式ドキュメントがAngular / Ionicでの導入方法を出してくれているので、それに従います。
AWS Amplify関連パッケージのインストール
まずAWS Amplify関連のパッケージをインストールします。 aws-amplify-angular
というパッケージがあるのでそれを使います。
$ npm install aws-amplify aws-amplify-angular
Angular 6以上で必要となる設定を書く
window.global
と window.process
がセットされている必要があるとのことです。指示に従って以下の設定を src/polyfills.ts
に追記します。
(window as any).global = window;
(window as any).process = {
env: { DEBUG: undefined },
};
src/polyfills.ts
は最終的には以下のようになりました。Ionic CLI(Angular CLI)が説明のためのコメントを大量に書いてくれていますが、見やすくするために全て削除しています。
import './zone-flags.ts';
import 'zone.js/dist/zone';
(window as any).global = window;
(window as any).process = {
env: { DEBUG: undefined },
};
余談ですが、公式ドキュメントに、
Please also note that the AWS Amplify Angular components do not yet support Ivy.
と書いてありました。Ivyのサポートはまだ無いようですね...
TypeScriptのコンパイルオプションを調整する
src/tsconfig.app.json
内の compilerOptions
セクションの types
に node
を追加します。ちなみに、 src/tsconfig.json
というファイルもあるので混同しないよう注意が必要です。
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": ["node"]
},
"include": [
"src/**/*.ts"
],
"exclude": [
"src/test.ts",
"src/**/*.spec.ts"
]
}
これでIonicアプリへのAWS Amplify JavaScript Frameworkのインストールは完了です。
AWS Amplifyの初期設定を行う
AWS Amplify CLIを使って初期設定を行います。初期設定はプロジェクトごとに行う必要がある操作になります。
# Amplify CLIの初期設定を開始
$ npx amplify init
# プロジェクト名を指定
? Enter a name for the project AmplifyIonicChat
# 環境名を指定
? Enter a name for the environment dev
# エディタを指定
? Choose your default editor: Visual Studio Code
# 開発に使う言語を指定
? Choose the type of app that you re building javascript
# 開発に使うフレームワークを指定
? What javascript framework are you using ionic
# ソースコードのディレクトリを指定
? Source Directory Path: src
# ビルド後の成果物の格納先ディレクトリを指定
? Distribution Directory Path: www
# ビルドコマンドを指定
? Build Command: npm run-script build
# 開発サーバー起動コマンドを指定
? Start Command: ionic serve
# Amplify CLIが使うAWSプロファイルを使う
? Do you want to use an AWS profile? Yes
# プロファイルを指定:今回は個人用のAWSに繋がるプロファイルとして用意してある「private」を指定
? Please choose the profile you want to use private
ここまで指定するとCloudFormationが起動して、バックエンドに必要なリソースを生成します。
ここでは以下のリソースが作成されます。「この時点で作るリソースあるの?」という感じですが、何か意図があるのでしょうか。。。
- S3バケット
- Cognitoフェデレーテッドアイデンティティでの認証済みクライアントが引き受けるロール(AuthRole)
- Cognitoフェデレーテッドアイデンティティでの未認証クライアントが引き受けるロール(UnauthRole)
AWS AmplifyのAuthenticationカテゴリを使ってユーザー認証を実装する
ここからはAWS Amplify CLIを使ってAWSクラウド上にバックエンドを構築していきます。
Authenticationカテゴリの設定をAmplify CLIで構築する
まずはアプリケーションにサインアップ・サインイン機能を作るために、AWS AmplifyのAuthenticationカテゴリをセットアップします。
こちらは公式ドキュメントの以下の箇所に沿って進めます。
# Amplify CLIを使ってAuthenticationカテゴリを追加
$ npx amplify add auth
# 認証の設定をどのように行うか指定:今回はデフォルトの設定を利用
Do you want to use the default authentication and security configuration? Default configuration
# サインインに使える属性を指定
How do you want users to be able to sign in? Username
# 追加の設定をするかどうかを指定
Do you want to configure advanced settings? No, I am done.
これで設定は完了です。この時点ではまだバックエンドに設定は適用されていません。
設定をバックエンドに適用する
では、実際に設定をバックエンドに適用します。
# 変更をバックエンドに適用
$ npx amplify push
# 変更内容が出るので、確認して先へ進む
Current Environment: dev
| Category | Resource name | Operation | Provider plugin |
| -------- | ------------------------ | --------- | ----------------- |
| Auth | amplifyionicchatd1aa1b6e | Create | awscloudformation |
? Are you sure you want to continue? (Y/n)
マネジメントコンソールで確認すると、Amazon Congitoのユーザープールが作成されていることがわかります。
Ionicアプリにバックエンドへの接続情報を適用する
先ほどの $ npx amplify push
コマンド実行のタイミングで、バックエンドの接続情報(CognitoのユーザープールIDやアイデンティティプールID等)が src/aws-export.js
というファイルに出力されました。
aws-export.js
は以下のようなシンプルなJSファイルです。
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
const awsmobile = {
"aws_project_region": "ap-northeast-1",
"aws_cognito_identity_pool_id": "<アイデンティティプールID>",
"aws_cognito_region": "ap-northeast-1",
"aws_user_pools_id": "<ユーザープールID>",
"aws_user_pools_web_client_id": "<ユーザープールクライアントID>",
"oauth": {}
};
export default awsmobile;
1行目にコメントで書いてある通り、このファイルは今後の $ npx amplify push
コマンド実行時に上書きされるので、手作業で変更してはいけません。
Amplify Frameworkを初期化する
Amplify Frameworkに aws-exports.js
に書かれた設定情報を読み込ませるため、 src/main.ts
に以下のようにAmplifyの初期化処理を書きます。
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
// 以下3行を追加
import Amplify from 'aws-amplify';
import awsconfig from './aws-exports';
Amplify.configure(awsconfig);
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
ちなみに、公式ドキュメントでは、 Amplify
のインポート元は @aws-amplify/core
となっていますが、そのまま書いてもうまくいかず以下のようなエラーが出てしまいます。
これを解消するために、 Amplify
は aws-amplify
から読み込むようにしています。
これでフロントエンドとバックエンドの接続が完了です。
Angularのモジュールの整理をしておく
ここで一旦今後のためにAngularプロジェクトとしての準備を行います。
- 未ログイン状態のときにアクセスできるページ群を管理する
PublicModule
を作成 - ログイン状態のときにアクセスできるページ群を管理する
ClosedModule
を作成 - アプリケーション全体から利用するモジュールをまとめた
SharedModule
を作成
Angularの「モジュール」
Angularでは、アプリケーションを「モジュール」という単位に分割できます。ページコンポーネントを一つのモジュールとして作成しておくことで、そのページが必要となったタイミングでモジュールごと読み込む遅延読み込み(Lazy Loading)ができます。
モジュールの定義には @NgModule
デコレータを使います。
あるモジュールAであるモジュールBを使いたい場合、モジュールBの定義箇所の @NgModule
の宣言内の imports
にモジュールAを指定します。
Angularには最上位のモジュールである AppModule
が存在します。
そして、 $ ionic start
コマンドでBlankテンプレートを選択して作成した雛形には、Homeページ用の HomeModule
も生成されています。
未ログイン状態でアクセスできるページ群を管理するPublicModuleを作成する
Ionic CLIを使ってモジュールを作成します。
$ npx ionic g module pages/public
これで、 src/app/pages/public/public.module.ts
が作成されます。中身は以下のようにしました。ルーティングは後ほど追加していくので、まだ何も作成していません。
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
// ここにルーティングの定義を書いていく
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forChild(routes)]
})
export class PublicModule { }
ログイン状態でアクセスできるページ群を管理するClosedModuleを作成する
PublicModule
と同様にモジュールを作成します。
$ npx ionic g module pages/closed
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
// ここにルーティングの定義を書いていく
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forChild(routes)]
})
export class ClosedModule { }
AppRoutingModuleにPublicModuleとClosedModuleを追加する
最後に、アプリケーションのルートのルーティング定義である AppRoutingModule
に PublicModule
と ClosedModule
を登録します。
これで PublicModule
や ClosedModule
に書いたルーティングが有効になります。
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
const routes: Routes = [
// 直下へのアクセスは /auth へリダイレクト
{ path: '', redirectTo: 'auth', pathMatch: 'full' },
// 未ログイン状態でアクセスできる画面群のルーティング
{
path: '',
loadChildren: () => import('./pages/public/public.module').then(m => m.PublicModule)
},
// ログイン状態でアクセスできる画面群のルーティング
{
path: '',
loadChildren: () => import('./pages/closed/closed.module').then(m => m.ClosedModule)
},
];
@NgModule({
imports: [
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
],
exports: [RouterModule]
})
export class AppRoutingModule { }
Angularでは、URLでの画面遷移を許可するかどうかを制御する「ガード」という仕組みがあります。このガードを PublicModule
と ClosedModule
にかけることで、ログイン状態のときはサインアップフォームへのアクセスはリダイレクト、未ログイン状態のときはサインアップフォームへリダイレクトといった制御をきれいに書くことができます。
アプリケーション全体で使うモジュールをまとめたSharedModuleを作る
前述の通り各ページはそれぞれ独立したモジュールになっているので、それらのモジュールで共通したい処理はまとめておくと楽です。
全ページで使う IonicModule
や FormsModule
等は全て SharedModule
に含めてしまい、各ページのモジュールからはこの SharedModule
のみインポートするようにします。
$ npx ionic g module shared
これで、 src/app/shared/shared.module.ts
が生成されました。
内容は以下のようにします。
import { NgModule } from '@angular/core';
import { IonicModule } from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { AmplifyIonicModule, AmplifyService } from 'aws-amplify-angular';
const modules = [
FormsModule,
IonicModule,
CommonModule,
AmplifyIonicModule,
];
@NgModule({
imports: [...modules],
exports: [...modules],
providers: [AmplifyService],
})
export class SharedModule { }
importを絶対パスで書けるようにする
ソースコードをディレクトリで整理していくと、 import
文が以下のようになったりします。
import { MyService } from '../../../../../services/myservice/myservice.service';
これだと辛いので、プロジェクトのルートディレクトリから絶対パスで指定できるようにしておきます。
tsconfig.json
の compilerOptions
に paths
を指定します。
{
"compilerOptions": {
(...略)
"paths": {
"@/*": ["src/*"]
},
(...略)
}
}
この設定を書くことによって、先ほどの import
文は以下のように書くことができます。
import { MyService } from '@/services/myservice/myservice.service`;
雛形で生成されていたAppModuleを調整する
後ほど AppComponent
でAWS Amplifyが提供する AmplifyService
を使うので、AppModule
でも SharedModule
をインポートするようにしておきます。
同時に雛形で生成されていた不要なモジュールのインポートも削除します。
import { NgModule } from '@angular/core';
import { RouteReuseStrategy } from '@angular/router';
import { BrowserModule } from '@angular/platform-browser';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { SharedModule } from './shared/shared.module';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
SharedModule,
IonicModule.forRoot(),
AppRoutingModule,
],
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
})
export class AppModule {}
雛形で生成されていたHomePageを調整する
最後に、整理したモジュールの構造の中に自動生成された HomePage
を入れます。
生成されたときは src/app/home/
にあった HomePage
の一式を src/app/pages/closed/
に移します。
そして、 src/app/pages/closed/home/home.module.ts
を以下のように調整します。
(FormsModule
/ IonicModule
/ CommonModule
のインポートを SharedModule
のインポートに置き換えました)
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { HomePage } from './home.page';
import { SharedModule } from '@/app/shared/shared.module';
@NgModule({
imports: [
SharedModule,
RouterModule.forChild([{ path: '', component: HomePage }])
],
declarations: [HomePage]
})
export class HomePageModule {}
最後に、 ClosedModule
に HomePage
のルーティングを定義します。
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
{
path: 'home',
loadChildren: () => import('./home/home.module').then(m => m.HomePageModule),
},
];
@NgModule({
imports: [
RouterModule.forChild(routes),
]
})
export class ClosedModule { }
結構調整作業が多くなってしまいました。本稿の主役はAWS Amplifyですが、せっかくなのである程度アプリケーションとしてスケールさせられる体制を整える方法まで書きたいと思っています。
認証を扱うページを生成する
先ほどバックエンドにAWSの認証基盤であるAmazon Cognitoを構築できたので、先ほど作ったIonicアプリでサインアップ・サインインできるようにします。
AWS Amplifyのすごいところは、サインイン周りを一発で実装できるコンポーネントを各フレームワークで用意してくれているところです(!)
具体的には、 <amplify-authenticator>
というコンポーネントが提供されていて、これをアプリケーション内に配置するとサインインフォームが出現します。
認証をWebアプリケーションに組み込む場合、
- サインアップ画面は
/sign-up
- サインイン画面は
/sign-in
- パスワードリマインダーは
/password
のようにそれぞれURLを分けることが一般的かと思います。
しかし、今回は認証周りを <amplify-authenticator>
コンポーネントを利用して行うため、認証を扱う画面は1つあれば十分です。
認証機能を配置するページを作成する
Ionic CLIを使って認証用の画面を用意します。CLIを使ってページを生成する場合、自動的にモジュールが作成され、遅延読み込みが有効になります。
認証を扱う画面は未ログイン状態でのみ閲覧可能としたいので、先ほど作成した PublicModule
以下にページのモジュールを作成します。
$ npx ionic g page pages/public/auth
これで以下のファイルが出来上がりました。
src/app/pages/public/auth/auth.page.ts
src/app/pages/public/auth/auth.page.spec.ts
src/app/pages/public/auth/auth.page.html
src/app/pages/public/auth/auth.page.scss
src/app/pages/public/auth/auth.module.ts
src/app/pages/public/auth/auth-routing.module.ts
今回はルーターの設定も auth.module.ts
に書いていくことにするので、 auth-routing.module.ts
は削除します。
認証用のページのモジュールである auth.module.ts
は以下のように記述します。
import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { SharedModule } from '@/app/shared/shared.module';
import { AuthPage } from './auth.page';
@NgModule({
imports: [
SharedModule,
RouterModule.forChild([{ path: '', component: AuthPage }]),
],
declarations: [AuthPage]
})
export class AuthPageModule {}
最後に、 /auth
でこのページにアクセスできるよう、 PublicModule
にルーティング定義を追加します。
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
{
path: 'auth',
loadChildren: () => import('./auth/auth.module').then(m => m.AuthPageModule),
},
];
@NgModule({
imports: [
RouterModule.forChild(routes),
]
})
export class PublicModule { }
これで /auth
ページの準備は完了です。 http://localhost:8100/auth
にブラウザでアクセスすると以下のような画面が表示されます。
AWS Amplifyが提供してくれている認証コンポーネントを配置する
では、作成した AuthPage
にAWS Amplifyが提供してくれている <amplify-authenticator-ionic>
コンポーネントを配置してみます。
<ion-header>
<ion-toolbar>
<ion-title>auth</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div class="ion-padding">
<amplify-authenticator-ionic></amplify-authenticator-ionic>
</div>
</ion-content>
Ionicを使わない素のAngularの場合、 <amplify-authenticator>
コンポーネントを利用しますが、Ionicを使う場合は専用の <amplify-authenticator-ionic>
コンポーネントを使うことができます。
なんとこれだけで認証周りの画面の実装が完了します。
試しにサインアップしてみる
表示されているサインイン画面の下の方の「Create account」をクリックします。
すると、サインアップ画面に遷移します。
遷移する、といっても <amplify-authenticator-ionic>
コンポーネントがサインアップフォームのUIに変わるだけでルーティングは変わりません。
サインアップフォームで情報を入力します。
デフォルトの設定では、以下の項目を入力する必要があります。
- ユーザー名
- メールアドレス
- パスワード(英数字 + 記号 / 8文字以上)
- 電話番号(
090
の先頭のゼロは取る)
これで「Create Account」をクリックするとCognitoユーザープールにアカウントが作成されます。
メールアドレスの開通確認もデフォルトで用意されているので、入力したメールアドレスの受信トレイを確認します。
シンプルなメールが届いていました。
サインアップすると <amplify-authenticator-ionic>
コンポーネントは自動的に以下のようなメールアドレス開通確認コード入力画面に切り替わるので、メールで届いた6桁の確認コードを入力します。
「Confirm Code」をクリックするとサインアップが完了します。サインアップ後は改めてログインする必要があります。
登録したアカウント情報でサインインすると、<amplify-authenticator-ionic>
コンポーネントは以下のようなUIに切り替わりました。
(ちなみにちょいちょいconsoleに出ているエラーはアカウント情報を何度か入力し間違えたためです💦)
これでIonicアプリにAWS Amplifyを使って認証システムを組み込むことができました。
認証周りは実は結構複雑で、以下のような画面をユーザーの状態に応じて出し分ける必要があります。
- サインアップ
- メールアドレスの開通確認
- サインイン
- パスワードリマインダー
- パスワード再設定
AWS Amplify JavaScript Frameworkを使うことでこの辺りをコンポーネント一発で構築できるのは非常に強力です。
Amplifyの認証状態をIonicアプリに同期する
さて、準備の段階で頑張って PublicModule
と ClosedModule
を作って、未認証状態と認証状態の画面群を分けました。
サインインは <amplify-authenticator-ionic>
コンポーネントで行えばよいですが、Amplifyが内部的に持っているログイン状態に応じてルーティングを変えたいです。
AppComponentにAmplifyの認証状態を監視するコードを追加する
Ionicアプリのルートコンポーネントとして、 AppComponent
というコンポーネントがあるので、そこでAmplifyの認証状態を監視してルーティングに反映させようと思います。
Ionic CLIでプロジェクトを作ると、 AppComponent
にはネイティブアプリ向けのスプラッシュスクリーンやステータスバーの操作処理が書かれていますが、今回は必要ないのでガンガン削除します。
完成形のみ書きます。
import { Component, OnInit } from '@angular/core';
import { NavController } from '@ionic/angular';
import { AmplifyService } from 'aws-amplify-angular';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss']
})
export class AppComponent implements OnInit {
constructor(
private navCtrl: NavController,
private amplifyService: AmplifyService,
) {}
ngOnInit() {
this.amplifyService.authStateChange$.subscribe(authState => {
switch (authState.state) {
case 'signedIn':
this.navCtrl.navigateForward(['/home']);
break;
case 'signedOut':
this.navCtrl.navigateForward(['/auth']);
break;
}
});
}
}
Observable
を subscribe
するときは、必要なくなったときに必ず unsubscribe
しないとメモリリークにつながりますが、こと AppComponent
に関してはアプリケーションが生きている間はずっと存在している間はずっと存在するので、特に unsubscribe
する処理は書いていません。
AmplifyをAngularから使うためには、aws-amplify
パッケージから個別に Auth
や API
をインポートしてもよいのですが、AngularにはDI(Dependency Injection)という強力な仕組みがあります。
aws-amplify-angular
パッケージでは、そのDI経由でAmplifyを操作できるように AmplifyService
というサービスクラスを提供してくれています。
また、AngularはRxJSと密結合です。AmplifyService
では、Amplifyが内部的に持っているログイン状態の変化をRxJSの Observable
として提供してくれています。(this.amplifyService.authState()
の部分)
この状態でサインインすると、自動的に HomePage
に遷移します。
とりあえずHomePageにサインアウトボタンを設置する
サインアウトも試したいので、 HomePage
にサインアウトボタンを設置します。Ionicを使っているので、ヘッダーにアイコンを使ったボタンを設置するのは一瞬でできてしまいます。
<ion-header>
<ion-toolbar>
<ion-title>
Ionic Blank
</ion-title>
<!-- ここから追加 -->
<ion-buttons slot="end">
<ion-button slot="icon-only" (click)="onSignOutButtonClicked()">
<ion-icon name="log-out"></ion-icon>
</ion-button>
</ion-buttons>
<!-- ここまで追加 -->
</ion-toolbar>
</ion-header>
<ion-content>
<div class="ion-padding">
The world is your oyster.
<p>If you get lost, the <a target="_blank" rel="noopener" href="https://ionicframework.com/docs/">docs</a> will be your guide.</p>
</div>
</ion-content>
続いて src/app/pages/closed/home/home.page.ts
にサインアウト処理を書いていきます。こちらも AmplifyService
をDIして、用意されているメソッドを使えば簡単にできます。
import { Component } from '@angular/core';
import { AmplifyService } from 'aws-amplify-angular';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
constructor(
private amplifyService: AmplifyService,
) {}
onSignOutButtonClicked() {
this.amplifyService.auth().signOut();
}
}
こんな感じで動作します。いい感じですね!
ここまででIonicアプリにAmplify Frameworkを組み込むことができました。
続きは続編にて:AWS AppSyncのセットアップとリクエスト
ここまでの作業をまとめると、
- Ionic CLIを使ってIonicプロジェクトを作成
- Amplify CLIを使ってバックエンドにAmazon Cognitoを構築
- Amplify Frameworkをセットアップ
- Amplify提供の
<amplify-authenticator-ionic>
コンポーネントを使って認証周りをサクッと構築 - Amplifyが持つ認証状態をAngular側で監視してルーティングを切り替える
になります。
一番書きたかったのはAWS AppSyncでGraphQL APIを作成してAWS Amplify JavaScript Frameworkから叩く部分でしたが、予想以上に準備の手順が多かったのでこのあたりで一旦切りたいと思います。
今回がQiitaのアドベントカレンダー初挑戦なのでこんな感じで良いのか若干不安ですが、勢いで2日間書くことにしているので、続編は12/17の記事でお送りできたらと思います。
ざっくりですが、この後はAWS AppSyncを使ってAPIを立てて、リアルタイムで同期されるチャットアプリを作ろうと思っています。
チャットアプリはAppSyncの練習としてよく題材にされているイメージです。
awslabsにもChatQLというAngular+AppSyncのサンプルがあったり。
この後の実装はチャットアプリに寄せたものになっていく予定ですが、本記事の内容は割と汎用性のあるものに仕上げたつもりです。
AWS Amplifyでバックエンドを爆速開発できるのに加えて、Ionicでフロントエンドも爆速開発できたらより夢が広がりませんか!?
AWS Amplify Advent Calendar、明日は @moaible4qiita さんです!