Amplify Frameworkの新しい認証UIコンポーネント（@aws-amplify/ui-react）を試そう

## Amplify Frameworkとは
AWSがOSSとして提供している開発プラットフォーム。CLIでコマンドを叩くだけで認証やAPI、ストレージなどをAWS上にいい感じに構築してくれるスグレモノ。

最初の環境構築方法などは[他の記事](https://qiita.com/t_okkan/items/38aca98993bf06598af6#%E8%AA%8D%E8%A8%BC%E6%A9%9F%E8%83%BD%E3%81%AE%E8%BF%BD%E5%8A%A0)やサイトに書かれているのでそちらを参照していただきたい。

ただし、今回は
```npm install aws-amplify-react```
でaws-amplify-reactをReactアプリに組み込むことはせず、代わりに
```npm install @aws-amplify/ui-react ```
を叩いて@aws-amplify/ui-reactを使用する。

## 認証画面の表示がおかしい・・・
本題に進む前にAmplify Frameworkを触っていて起きたことについて少しだけ書くと、
数多ある「Amplify Frameworkで認証画面を爆速で作ってみよう」系の記事を参考に
胸を躍らせながらAmplifyのコマンドを叩いてAWS環境を構築し、クライアントにパッケージを入れ、
いざ```npm start```を快音高らかに叩いた時に悲劇が起きた。

![Failed_Auth](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362251/8e76ba34-5da4-134d-b86d-deac46b82c2f.png)

**なにこれ・・・？**

やべぇ・・・同じ手順で進めたはずが、クソださ認証画面を生み出してしまった。
何か間違えてたかと虱潰しに手順を確認するも特に異常なし。
途方に暮れながらGoogle先生にお伺いを立てていると天啓が届いた。

## 「それレガシーですよ」
[公式ドキュメント](https://docs.amplify.aws/ui-legacy/q/framework/react)ではすでに```aws-amplify-react```はLegacyと書かれているではないですか！（知らんかった・・・）

[AWSのブログ](https://aws.amazon.com/jp/blogs/mobile/amplify-framework-announces-new-rearchitected-ui-component-and-modular-javascript-libraries/)を見ると4月にはすでに発表されてるじゃないですか！（知らんかった・・・）

というわけで自分の無知に深く恥入りながらも、早速```@aws-amplify/ui-react```を使って認証機能を作っていきましょうという次第であります。

（画面が変になったのはこのLegacyのせいなのかは実はちょっとハッキリしていません・・・（小声））

## まずは基本のAmplifyAuthenticator
```React:App.js
import React from 'react';
import Amplify from 'aws-amplify';
import { AmplifyAuthenticator } from '@aws-amplify/ui-react'; 
import awsconfig from './aws-exports';

Amplify.configure(awsconfig);

const App = () => (
  <AmplifyAuthenticator>
    <div>
      My App
    </div>
  </AmplifyAuthenticator>
);

export default App;
```

実装はとてもシンプルで```@aws-amplify/ui-react```からAmplifyAuthenticatorをApp.jsにインポートして
認証通過後の画面要素を挟んであげるだけ。
#### SignIn画面
![SignInPage1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362251/8421c96e-b807-872c-f4fd-a233595b1dbb.png)
#### SignUp画面
![SignUpPage1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362251/3354f0e9-b634-e220-2604-a48a8a8d1a0e.png)

これだけで冒頭でお見せしたクソださ認証画面ではなく、ちゃんと綺麗な認証画面が出来上がった。とりあえず一安心。

## 入力項目をカスタマイズ

@aws-amplify/ui-reactではSign-inやSign-upの入力項目や必須か否かをカスタマイズすることができる。

まずはSign-in画面のUsernameのカスタマイズから。

デフォルトでは任意のUsernameを入力することになっているが、ここでメールアドレスを利用可能にする。

まずはCognitoの認証方式でメールアドレスをUsernameとして利用できるようにしておく。（[参考サイト](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-aliases-settings-option-2)）

Amplify FrameworkのCLIですでにメールアドレスをUsernameとして利用可能にしておいた場合は設定不要だ。

あとは以下のように先ほど書いたAmplifyAuthenticatorのusernameAliasプロパティに"email"を渡してあげればOK。

```React:App.js
const App = () => (
  <AmplifyAuthenticator usernameAlias="email"> {/* <- ここで設定 */}
    <div>
      My App
    </div>
  </AmplifyAuthenticator>
);
```
![Sign-in2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362251/7a1c1d3a-5810-733f-66f4-b92c017f5bfe.png)

先ほどのSing-in画面と比べてUsernameの項目がEmail Addressに変更されている。
ここを電話番号にしたい場合はCognitoの設定後にusernameAliasに"phone_number"を渡すことで実現できる。

次にSign-upの入力項目が多すぎるなと感じたので減らしてみよう。

```React:App.js
import { AmplifyAuthenticator, AmplifySignUp } from '@aws-amplify/ui-react';
```
まずは@aws-amplify/ui-reactからAmplifyAuthenticatorに加えてAmplifySignUpをインポート。

```React:App.js
const App = () => (
  <AmplifyAuthenticator>
    <AmplifySignUp
      slot="sign-up"
      usernameAlias="email"
      formFields={[
        {
          type: "email",
          label: "Email address",
          placeholder: "Enter your email address",
          required: true,
        },
        {
          type: "password",
          label: "Password",
          placeholder: "Enter your password",
          required: true,
        },
      ]}
    ></AmplifySignUp>
    <div>
      My App
    </div>
  </AmplifyAuthenticator>
);

export default App;
```
あとはAmplifySignUpを最初の画面の前にプロパティを加えて入れてあげればOK。

slotはAmplifyのUIコンポーネントをカスタマイズするために必要なプロパティ。他にもコンポーネントに合わせたslotがあるので
[ここ](https://docs.amplify.aws/ui/auth/authenticator/q/framework/react#slots)を参考に必要なslot名を入れる。（AmplifySingInならslot="sign-in"といった具合）

usernameAliasは先ほどのSign-in画面のカスタマイズの時と同様、Usernameにメールアドレスを使用可能にするプロパティ。

formFieldsは入力項目をカスタマイズするためのプロパティ。配列の中のオブジェクトによって入力項目を制御できる。

typeで入力項目の種類、labelで入力欄の上に表示される文字、placeholderで入力欄に表示されるプレースホルダー、そしてrequiredで必須項目か否かを指定することができる。

今回はメールアドレスとパスワードの２つの必須項目を設定した。

![Sign-up2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362251/57c37bf0-4aea-ffdf-f8b2-b8bd42f25c6e.png)

これでアカウント作成が可能になったので早速作ってみる。Sign-up画面の項目を入力してCREATE ACCOUNTをクリックすると確認画面が表示される。

![Confirm page](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362251/8c4a91b7-e6ae-b88f-69d7-cce2b470d130.png)

登録したメールアドレスに確認用の６桁のコードが送信されるのでそれを入力すれば確認完了。アプリにサインインできるようになる。

## サインアウト
これでサインインする準備ができた。サインインできるならサインアウトも必要だ。サインアウトの実装も至って簡単。

```React:App.js
import { AmplifyAuthenticator, AmplifySignUp, AmplifySignOut } from '@aws-amplify/ui-react';
```
まずはAmplifySignOutを@aws-amplify/ui-reactからインポートする。

```React:App.js
const App = () => (
  <AmplifyAuthenticator usernameAlias="email">
    <AmplifySignUp
      slot="sign-up"
      usernameAlias="email"
      formFields={[
        {
          type: "email",
          label: "Email address",
          placeholder: "Enter your email address",
          required: true,
        },
        {
          type: "password",
          label: "Password",
          placeholder: "Enter your password",
          required: true,
        },
      ]}
    ></AmplifySignUp>
    <div>
      My App
      <AmplifySignOut /> {/* <- ここに追加 */}
    </div>
  </AmplifyAuthenticator>
);
```
あとは画面の好きなところに<AmplifySignOut />を入れてあげれば完成。

![Sign out](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362251/6ed2aac4-e093-b32c-86fc-390936131b63.png)

サインインすると最初の画面に横長なSing-outボタンが表示された。

ボタンの文言を変更したいときは以下のようにbuttonTextプロパティに指定の文言を渡してあげれば変えることができる。

```React:App.js
<AmplifySignOut buttonText="Custom Sign Out Button"/>
```
![Sign out2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362251/fda7cf13-1110-2725-5153-f48c402b2ca7.png)

（小文字で書いても大文字になっちゃうみたい・・・）

## ちょっとだけ問題点

#### 追記（2020/8/3）
コメントにある通り、Amplifyの[公式サイト](https://docs.amplify.aws/ui/customization/theming/q/framework/react#managing-layout)にログイン画面の配置を真ん中にするCSSのテンプレートがあった。
index.cssに以下を記述することでログイン画面が真ん中に表示された。
新コンポーネントを利用する際は忘れずに記載するようにしよう。
（ずっとApp.cssの方に記載して「全然反映されねぇ…」と少し焦ったのは内緒。）

```css:index.css
amplify-authenticator {
  display: flex;
  justify-content: center;
  align-items: center;
  flex: 1;
  height: 100vh;
}
```
---
~~とっても簡単に認証画面周りを構築してくれるAmplify Frameworkの新コンポーネントだが、少しだけ問題点もあった。~~（※追記で解決済み）

上記では認証コンポーネントのみを切り抜いてスクショしていたのでわからなかったが、実は下のように左上にデフォルトで表示されてしまうのだ。

![Sing In3](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362251/c9578935-48f1-75ee-4ab4-ac77c2d43506.png)

Legacy版のwithAuthenticatorを使っていた場合だとデフォルトでスクリーンの真ん中に表示されていたが、新バージョンはそこまで気を利かせてはくれないらしい。

[Issue](https://github.com/aws-amplify/amplify-js/issues/5775)もまだOpen状態なので今後改善されるのを待つしかなさそう。

```React:App.js
<AmplifyAuthenticator usernameAlias="email" style={{ textAlign: 'center', margin: 0 }}>
```
こんな感じでstyleを適用してみても横方向の真ん中に設定できるくらいだった。（・・・ので誰か知恵をお貸しください（ﾎﾞｿｯ））

ちなみに新バージョンにもwithAuthenticatorはあるので以下のように使えばサインイン画面を真ん中に表示させることはできる。

```React:App.js
import React from 'react';
import { withAuthenticator, AmplifySignOut } from '@aws-amplify/ui-react';

const App = () => (
  <div>
    <AmplifySignOut />
    My App
  </div>
);

export default withAuthenticator(App);
```
ただしこれだとAmplifySingUpの入力項目カスタマイズができなかった。（調査不足でできたらゴメンナサイ・・・）

ここら辺のデザイン周りが調整されればあとは完璧かなと感じた。画面のど真ん中にこだわらない方であれば横方向の真ん中までなら配置できるので問題ないはず。

## まとめ
Amplify FrameworkはCLIを操作するだけでバックエンド、フロントエンド両方をいい感じに作ってくれる便利なフレームワーク。

新しいUIコンポーネントでも手軽に項目の操作などができ、認証周りの開発はとても捗りそう。

ここで述べた他にもカスタマイズ可能な項目やコンポーネントはたくさんあるので今後も調べながら使ってみたい。

また記事中に何か不足している点などがあれば是非ご指摘いただければ助かります。

### 参考
* [Amplify Docs](https://docs.amplify.aws/ui/auth/authenticator/q/framework/react)
* [AWS Amplify　はじめてみる編](https://qiita.com/t_okkan/items/38aca98993bf06598af6)
* [【Amplify】AWS Amplify の UIコンポーネントが新しくなってた話](http://blog.serverworks.co.jp/tech/2020/06/17/amplify-new-ui-components/)
* [AWS Mobile Blog](https://aws.amazon.com/jp/blogs/mobile/amplify-framework-announces-new-rearchitected-ui-component-and-modular-javascript-libraries/)