AWS再入門ブログリレー AWS Amplify編

2020.08.17

どうも、コンサル部のもこ@札幌オフィスです。

当エントリは弊社コンサルティング部による『AWS 再入門ブログリレー 2020』の 10日目のエントリです。

このブログリレーの企画は、普段 AWS サービスについて最新のネタ・深い/細かいテーマを主に書き連ねてきたメンバーの手によって、 今一度初心に返って、基本的な部分を見つめ直してみよう、解説してみようというコンセプトが含まれています。

AWS をこれから学ぼう!という方にとっては文字通りの入門記事として、またすでに AWS を活用されている方にとっても AWS サービスの再発見や2020年のサービスアップデートのキャッチアップの場となればと考えておりますので、ぜひ最後までお付合い頂ければ幸いです。

では、さっそくいってみましょう。10日目のテーマはAWS Amplifyです。

AWS Amplifyとは?

AWS Amplify(以下Amplify)とは、AWSを利用してモバイルアプリケーションとウェブアプリケーション(SPA(Single Page Application))を開発する上で使えるフレームワークとホスティングサービスで、Amplifyを利用するとビルド・デプロイなどのCI/CDパイプラインを構築する手間が無くなったり、サーバーレスな構成なので運用が楽で低コストで、AppSync(GraphQL)やCognitoなどの連携もSPAのフレームワークレベルで提供されるSDKとUIコンポーネントを利用して爆速で開発を進めることができます。

本記事では、ウェブアプリケーション(React)開発の視点で紹介していきます。

Amplifyのサービスと機能一覧

Amplifyは大きく分けて、静的ホスティングやCI/CDなどの機能を備えた「Amplify Console」とライブラリーやUIコンポーネントとCLIを提供する「Amplify Framework」に分類する事ができます。

早速Amplify ConsoleとAmplify Frameworkについてご紹介していきます。

Amplify Console

Amplify Consoleでは、アプリケーションのビルド・テスト・デプロイ・ホスティングとドメインの管理、GitHubなどのGitプロバイダーと連携したCI/CD、Basic認証の設定機能などがあります。

Amplify Consoleのホスティングは内部的にCloudFront+S3を利用しているため、スケーラブルで負荷に強いと言えるでしょう

Amplify Consoleを使ったCI/CDについては後述しますが、開発環境のブランチが出来たら新しい環境を作ってデプロイ、開発環境のブランチが消えたら環境を削除するような事もできます。

Amplify Framework

Amplify Frameworkはライブラリ、UIコンポーネント、CLIの機能をまとめてAmplify Frameworkと総称します。

Amplify FrameworkはReact, Vue.js, Angularなど、フロントエンドのフレームワークレベルで提供されています。

ライブラリとUIコンポーネントを利用すると、割と実装に工数の掛かる認証(Cognitoとの連携)やログイン画面などをアプリケーションに簡単に、サクッと組み込むことができます。

Amplify FrameworkではStorageやCognito、Pinpointなど様々なAWSサービスと連携する事が出来ますが、特にAppSync(+Cognito)との連携がとても良くて、 schema.graphql にスキーマを書いて環境に適用するだけでGraphQLのResolverとクエリが自動生成されるため、入れるデータとスキーマを書くだけでOKです。

AWS Amplifyのメリット、デメリット

Amplifyで使える機能について軽く再入門したところで、Amplifyを利用する事によるメリデリを振り返っていきましょう。

メリット

  • とにかく爆速で開発が出来る
    • CI/CDパイプラインを作る必要がない
    • サーバーレス構成+SPA構成なので、運用が楽で負荷に強いアーキテクチャを簡単に組める
    • 登録/ログインの機能と画面はUIコンポーネントとして提供されているので、作り込みが不要。
      • 工数を削減してサービスを作れるので、プロトタイプ作成など捗る
    • Amplify+AppSync(+DynamoDB)との連携で、GraphQLのResolverとQuery/Mutation/SubscriptionのGraphQLクエリを自動生成してくれる
      • schema.graphql にスキーマを書いて、Amplifyが自動生成するFunctionを叩くだけでOK、Resolverの実装は基本不要
  • GraphQLのバックエンドDBとしてDynamoDBを使える!
  • やすい、文字通りのスモールスタートが簡単に出来る
    • 2020年8月17日時点の料金
      • ビルド1分あたり0.01$
      • ストレージ1GBあたり0.023$/月
      • ホスティングサービス(トラフィック)1GBあたり0.15$

デメリット

  • Webに関してはSPA(React, Vue.js, Angularなど)が前提で作られているようなサービスなので、SPAでないアプリケーションをマイグレーションする事は出来ない
  • 現にSPAをプロジェクトなどで導入していない場合、React, Vue.js, AngularなどのSPA関連の技術、知識も習得する必要がある
    • SPA関連の技術はトレンディなのでこれを機に学んでおいて損はないと思う!(個人的感想)
  • Amplify単体では現時点(2020/8/17)でSSR対応していない

Amplify Console + Amplify CLIを利用してHello Worldする

早速Amplifyを触っていきましょう。 create-react-appで新しいReactアプリケーションを作って、Amplify CLIの初期設定をして、GitHubと連携させていきたいと思います。

まずはプロジェクトの作成からです。 create-react-app をして、 yarn start していきましょう。

$ npx create-react-app amplify-reintroduction --typescript
$ cd amplify-reintroduction/
$ yarn start

Hello World用の下地が出来上がったところで、Amplify CLIを導入して、プロジェクトの初期設定をしてきます。

$ npm install -g @aws-amplify/cli

$ amplify init 
Scanning for plugins...
Plugin scan successful
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project amplifyreintroductio # プロジェクト名文字数制限に引っかかってしまった
? Enter a name for the environment dev
? Choose your default editor: IntelliJ IDEA
? Choose the type of app that you're building javascript
Please tell us about your project
? What javascript framework are you using react
? Source Directory Path:  src
? Distribution Directory Path: build
? Build Command:  npm run-script build
? Start Command: npm run-script start
Using default provider  awscloudformation

For more information on AWS Profiles, see:
https://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html

? Do you want to use an AWS profile? Yes
? Please choose the profile you want to use test
Profile test is configured to assume role
  arn:aws:iam::xxxxxxxxxxxx:role/xxxxxxxxxxxx
It requires MFA authentication. The MFA device is
  arn:aws:iam::xxxxxxxxxxxx:mfa/xxxxxxxxxxxx
? Enter the MFA token code: xxxxxx
Adding backend environment dev to AWS Amplify Console app: d380bdb6rebw3t
⠙ Initializing project in the cloud...

amplify init コマンドを実行して簡単なウィザードで環境を選択していくと、CloudFormationが実行されてAWS上にAmplifyのリソースが作成されます。

実行が終わるとAmplify CLI上でデプロイを始めたりできますが、せっかくなのでAmplifyのGit連携でCI/CDを設定してみましょう。

ひとまずGitHubで新しいリポジトリを作って、先程のコードをPushします。

$ git remote add origin git@github.com:mokocm/amplify-reintroduction.git
$ git add .
$ git commit -m "added amplify"
$ git push

AWSマネジメントコンソールから先程作成したアプリケーションを開いて、GitHubと接続していきます

GitHubとの認証・認可を済ませてリポジトリを選択して、次へで進みます

次の画面でビルドの設定ができますが、Amplifyが自動で良い感じにやってくれます、新規開発の場合に関しては特に変更せず次へと進んで、

保存してデプロイを押すだけで完了です。GitHubとの連携の所要時間は1分ちょいで、簡単に設定できます。

数分待つとGitHubからソースコードを取得して、ビルド〜デプロイまでされていく様子を観察する事ができます。

デプロイが終わり、表示されているURLを開くと、無事稼働していることを確認できます!

Amplify + AppSyncを組み合わせて使ってみる

さて、やっと本題です。AmplifyとAppSyncを使ってデータの入出力をやってみましょう。

まずはじめに、Amplify FrameworkとUIコンポーネントをyarn addしていきます。

$ yarn add aws-amplify @aws-amplify/ui-react

続いてAmplifyコマンドを使って、GraphQLなAPIを作っていきます。

$ amplify add api
? Please select from one of the below mentioned services: GraphQL
? Provide API name: amplifyreintroductio
? Choose the default authorization type for the API Amazon Cognito User Pool
Using service: Cognito, provided by: awscloudformation

 The current configured provider is Amazon Cognito. 

 Do you want to use the default authentication and security configuration? Default configuration
 Warning: you will not be able to edit these selections. 
 How do you want users to be able to sign in? Email
 Do you want to configure advanced settings? No, I am done.
Successfully added auth resource
? Do you want to configure advanced settings for the GraphQL API No, I am done.
? Do you have an annotated GraphQL schema? No
? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)

The following types do not have '@auth' enabled. Consider using @auth with @model
     - Todo
Learn more about @auth here: https://docs.amplify.aws/cli/graphql-transformer/directives#auth


GraphQL schema compiled successfully.

? Do you want to edit the schema now? No

作成が終わったら、生成されたGraphQLのスキーマを見てみましょう。 ( amplify/backend/api/${backendname}/schema.graphql に保存されます。 )

ToDoテンプレートを選択したときに作成される schema.graphql は下記のようになっています。

type Todo @model {
  id: ID!
  name: String!
  description: String
}

スキーマを確認出来たら、amplify pushで、AWS環境に適用していきます。

$ amplify push 
✔ Successfully pulled backend environment dev from the cloud.

Current Environment: dev

| Category | Resource name                | Operation | Provider plugin   |
| -------- | ---------------------------- | --------- | ----------------- |
| Auth     | amplifyreintroductioa6d7a40b | Create    | awscloudformation |
| Api      | amplifyreintroductio         | Create    | awscloudformation |
? Are you sure you want to continue? Yes

The following types do not have '@auth' enabled. Consider using @auth with @model
     - Todo
Learn more about @auth here: https://docs.amplify.aws/cli/graphql-transformer/directives#auth


GraphQL schema compiled successfully.

pushするタイミングで、GraphQLのクエリーを直書きする事無くJavaScript/TypeScript上で入出力できるAPIを生成するのかを聞かれますので、Yesと答えていきます。

? Do you want to generate code for your newly created GraphQL API Yes
? Choose the code generation language target typescript
? Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.ts
? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions Yes
? Enter maximum statement depth [increase from default if your schema is deeply nested] 2
? Enter the file name for the generated code src/API.ts

しばらくしてデプロイが完了したら、早速コードを書いていきましょう。

認証画面とログイン後の画面の出し別け実装

認証部分と、認証後に出すコンポーネントを別けて実装してみました。

onAuthUIStateChange を使って状態を取得して、 SignedInしていない場合は AmplifyAuthenticator でUIコンポーネントの認証画面を表示させていきます。

App.tsx

import React, {useEffect} from 'react';
import './App.css';
import Amplify from "aws-amplify";
import {AmplifyAuthenticator, AmplifySignOut} from '@aws-amplify/ui-react';
import {AuthState, onAuthUIStateChange} from '@aws-amplify/ui-components';
import awsmobile from './aws-exports';
import Todos from './Todos';

Amplify.configure(awsmobile);

const App = () => {
  const [authState, setAuthState] = React.useState<AuthState>();

  useEffect(() => {
    return onAuthUIStateChange((nextAuthState, authData) => {
      setAuthState(nextAuthState);
    });
  }, []);

  return authState === AuthState.SignedIn ? (
    <div className="App">
      <Todos/>
      <AmplifySignOut/>
    </div>
  ) : (
    <AmplifyAuthenticator/>
  );
}

export default App;

AmplifyAuthenticator で表示される画面はこんな感じで、Cognitoと画面の作り込みが不要ですぐにログイン/登録画面を出すことができます。

メールアドレスとパスワードを設定して登録を進めると、メールアドレスが正しいかの確認メールまで求めてくれます。これをコンポーネント1個で提供しているのがすごいです。

AppSyncからデータを入出力する

上記 App.tsx で認証済みかで出し分けを実装したところで、 Todo.tsx を用意していきます。

今回はこんな感じのコードを書いてみました。

ポイントは fetchTodosaddTodo の部分で、生成されている ./graphql/queries./graphql/mutations を使ってシンプルに実装出来ていることを確認できるかとおもいます。

import React, {Component, useEffect, useState} from 'react';
import './App.css';
import Amplify, {API, graphqlOperation} from "aws-amplify";
import {GraphQLResult} from '@aws-amplify/api/lib/types';
import {listTodos} from "./graphql/queries";
import {createTodo} from "./graphql/mutations";
import awsmobile from './aws-exports';
import {ListTodosQuery} from './API';

Amplify.configure(awsmobile);

type Todo = {
  id: string,
  name: string,
  description: string | null,
  createdAt: string,
  updatedAt: string,
}


const Todos: React.FC = () => {
  const [state, setState] = useState<Todo[]>([]);
  const fetchTodos = async () => {
    // query
    const response = (await API.graphql(
      graphqlOperation(listTodos)
    )) as GraphQLResult;
    const todos = response.data as ListTodosQuery;
    if (todos.listTodos != null) {
      setState(todos.listTodos.items as Todo[]);
    }
  };
  useEffect(() => {
    fetchTodos();
  }, []);

  const addTodo = async () => {
    try {
      // mutation
      await API.graphql(
        graphqlOperation(createTodo, {
          input: {
            name: "買い物",
            description: "トマトを買う"
          }
        })
      )
      fetchTodos()
    } catch (err) {
      console.log(err);
    }
  }
  return (
    <div>
      <ol>
        {state.map(item => {
          return (
            <div>
              <li>{item.name}</li>
              <ul>{item.description}</ul>
            </div>
          )
        })}
      </ol>
      <button onClick={addTodo}>AddTodo</button>
    </div>
  );
}
export default Todos;

src/queries に生成されるコードと graphqlOperation を利用することにより、欲しいデータや入力したいデータをinputに渡す形で実装できます。

出来上がったページがこんな感じで、ボタンを押すと addTodo が実行されてトマトを買いに行くTodoが追加されていきます。

AppSyncのデータソースとなっているDynamoDBのテーブルを見るとこんな感じで、レコードが追加されているのを確認できます!

まとめ

以上、『AWS 再入門ブログリレー 2020』の10日目のエントリ『AWS Amplify』編でした。AWS Amplifyを使うことでナウでイケてる(?)サーバーレスSPA構成で簡単に爆速で開発できて、AWSの各種サービスとシームレスに連携したAmplify Frameworkアプリケーションに組み込むことができ、今アツいGraphQLを使ったデータの入出力も出来てしまう素晴らしいサービスです。

簡単に始めることが出来るので、是非一度触ってみて下さい。

明日(8/18)は恩塚さんによる「Amazon Route 53」の予定です。お楽しみに!

参考

https://docs.amplify.aws/ https://docs.amplify.aws/lib/auth/getting-started/q/platform/js