AWS Amplifyを無理して使わなくてもいいケースについて挙げてみる

AWS AmplifyといえばAWSが提供しているフロントエンド開発者向けのライブラリやツールセットです。今回はそんなAWS Amplifyについてです。

はじめに

この投稿は2020年10月22の21時から開催予定のイベント(ライブストリーミング)で話す内容です。

serverless-newworld.connpass.com

もし間に合えば、かつ時間があればぜひライブ配信のほうにも参加ください。

あと、今回Amplifyを取り上げる理由は、以前このシリーズで取り上げるテーマとして何がいいかっていうアンケートを取った結果です。

AWS Amplifyのウリだったりいいところってのはこれまでにいろんなところで語られていると思うのでそちらにお譲りするとして、サーバーレス同様に現実世界の課題すべてを1つのソリューションだけで解決しようとするのはあまりおすすめしないよねってことで、そんな観点でまとめます。

(2020.10.22 update)

上記イベントのアーカイブを公開しています。


サーバーレスアンチパターン今昔物語 第六夜

チャンネル登録してくれると更新通知も飛ぶのでよろしくです。

おさらい

そうは言っても、地ならしがてら簡単にAmplifyの特徴についてまとめておきます。

まず、AWS Amplifyと一言で言っても、いくつかの構成要素がありましてAmplify Library、Amplify UI Component、Amplify CLI、Amplify Consoleから構成されます。LibraryとUI Componentは区別していないこともありますが、わかりやすく言うとフロントエンドアプリケーションの開発に使うもの、バックエンドの構築・設定に使うもの、ビルド/デプロイ/ホスティングに使うものにわかれてると捉えてもらうといいでしょうか。

で、その特徴としてもいろいろあげられていますが、とても乱暴な表現であることをあえて承知で言いますと、

バックエンドにAWSを使ったフロントエンドアプリケーションを(全て手動でやるよりは比較的)手軽に開発するためのもの

と言えるでしょう。この説明に多方面からツッコミが入りそうな気はするが今回の本題ではないので気にしない。

フロントエンドアプリケーションと言っているとおり、JavaScript / iOS / Androidあたりに対応しています。JSについてはReact/Vue/Angularに加えて、ReactNativeとIONICに対応しています。今をときめくFlutterについてもDeveloper Previewとして対応されています。あ、最近Server Side Rendering(SSR)にも対応しました。その他、細かい特徴とかは公式のドキュメントやAWSがやってるセミナーの動画とかを見てもらうととても詳しく説明されています。

ちなみに今回取り上げるのは主にLibraryとCLIに関連する話、つまりAmplifyを使った開発そのものに関わる話。デプロイやホスティングをしてくれるAmplify Consoleに関してはほとんど触れません。というか、Amplify ConsoleについてはSPA(Single Page Application)やSSG(Static Site Generation)のアプリケーションをAWSで簡単にGitを中心としたデリバリパイプラインを作って公開するにはとてもいいものだと思う。Jamstackなんかはビルド9割だと思っていて、そのくらいコンテンツの更新からビルドおよびデリバリのパイプラインが重要だと思うのでそういうときにAmplify Consoleは便利だと思う。

AWSアカウントが必要ってのはあるけど持ってるならばとてもいいと思います。僕も個人的な用途で使っています。

AWS Amplifyはフロントエンド開発者にとっての銀の弾なのか

はい、もちろん違います。そもそも前述のとおりバックエンドをAWSで開発していない限り嬉しさも少ないです。というかゼロだと思います。あくまでもバックエンドにAWSがいる前提で使うもの。

自分が話をすることの多いサーバーレス関連でもよく言ってるのですが『最大のアンチパターンはすべてをサーバーレスにすることにこだわること』と言っています。

そしてこれはあらゆるものに当てはまると思っています。使い古された言葉ですが銀の弾などないのです。もちろんAWS Amplifyについても同様です。

その上でAWS Amplifyについて言うなれば、先ほども言ったとおりAWS Amplifyはあくまでも手動でもできることを比較的手軽にやれるようにしてくれているものです。フロントエンド開発者フレンドリーに。

つまり、言い換えるとAWS Amplifyじゃないとできないことは正直なところほとんどありません。

さらに言うとAWS Amplifyで対応していたとしても実際のところAmplify使ってやるより別の方法のほうがいいんじゃない?って思う点も個人的にはいくつかあります。

無理して使わなくてもいいケース

バックエンド側のライフサイクルや開発部隊が分かれてる場合

先ほども言ったようにAmplifyのメリットはフロントエンドから見たときにバックエンドを簡単に扱えることがメリットです。なのでこのケースの場合はAmplify使うメリットが薄まると思っています。

Amplifyを使う場合ってバックエンドはAmazon API Gateway + AWS Lambdaを使ったサーバーレスなREST APIAWS AppSyncを使ったGraphQL、もしくはAmazon S3などのようにAWSサービスやそのリソースをAPI経由で直接操作するパターンかと思います。

なかでも、REST APIを作る場合においてバックエンド側のライフサイクルや開発部隊が分かれている場合、フロントエンド側がバックエンドをいじることは少ないですよね。つまり、フロントエンドはバックエンドAPI作らないし、バックエンド側にとっても提供するものはAPIまでになるのでクライアントライブラリであるAmplifyは不要です。

また、これはあくまでも個人的な意見ですが、仮にフロントエンド開発者がREST APIまで作る場合だとしてもサーバーレスなリソースのプロビジョニングやデプロイを行うのはAWS SAMであったり最近だとAWS CDK使うほうが圧倒的にいいと思っています。餅は餅屋ということです。その中でも個人的にはAWS謹製ではないですがServerless Frameworkが好みです。理由はプラグイン機構とそのエコシステム、これに尽きる。

なぜ、Amplifyではなくこれらのほうがいいかというと、amplify add apiREST APIを作成するとLambda関数周りはこんな感じで生成されます。

amplify/backend/function/
|-- serverlessnewworld20d765121f
|   |-- amplify.state
|   |-- dist
|   |   `-- latest-build.zip
|   |-- function-parameters.json
|   |-- parameters.json
|   |-- serverlessnewworld20d765121f-cloudformation-template.json
|   `-- src
|       |-- event.json
|       |-- index.js
|       |-- package-lock.json
|       `-- package.json
`-- serverlessnewworld20e0fe6255
    |-- amplify.state
    |-- function-parameters.json
    |-- parameters.json
    |-- serverlessnewworld20e0fe6255-cloudformation-template.json
    `-- src
        |-- event.json
        |-- index.js
        `-- package.json

amplify pushすると作成したリソースをAWS上に反映するんですが、その際Lambda関数はデプロイパッケージにまとめられます。このツリーではamplify/backend/function/serverlessnewworld20d765121f/dist/latest-build.zipがそれです。これが関数ごとにできます。残念なのはこれを個別にデプロイできないんですよね。

また、API Gateway + Lambdaで完結するならまだいいですが大抵の場合はLambdaからアクセスする別のリソースが存在していることも多いです。そういったものについてはAmplifyの対象から外れてしまうんですよね。後述するやり方でできなくもないですが、それだったらシンプルにCDKやサーバーレス系のデプロイツールを使ったほうがいいと思います。

AWSのリソースに直接アクセスしない場合

フロントエンド側からAWSリソースに直接アクセスするケースっていろいろあるとは思いますが、多いのはAmazon CognitoとAmazon S3を利用する場合なのではないかと思います。

さて、ここでAWSリソースに直接アクセスするときのAmplifyの利点について簡単にお話すると、大きく2つの観点があります。1つはAmplifyがサポートしているものであればソースコードの記述がシンプルになるということ。もう1つはそれらリソースへのAmazon CognitoおよびAmazon Identity and Access Management (IAM)を使った認可が簡単に扱えるということです。

実際に以下は公式に載っているサンプルですがS3へのファイルアップロードだとこんな感じにかけます。

import { Storage } from 'aws-amplify';

~~

Storage.put('test.txt', 'Hello')
    .then (result => console.log(result))
    .catch(err => console.log(err));

とてもシンプルです。これだけでS3に対してファイルをpublicにアップロードできます。同じことを普通に書いたらこんな感じです。実際に動かして試してないのであくまでもイメージってことでお願いします。

var upload = new AWS.S3.ManagedUpload({
  params: {
    Bucket: sample,
    Key: "test.txt",
    Body: "Hello",
    ACL: "public-read",
  },
});

var promise = upload.promise();

promise.then(
  function (data) {
    console.log(data);
  },
  function (err) {
    console.log(err);
  }
);

簡単さがわかると思います。このあたりはまさにAmplifyの存在意義を示していると思います。バックエンドのAWSリソースをフロントエンド開発者フレンドリーな形で使いやすくなってますね。

一方、裏を返すとこの2点が不要な場合はAmplifyも不要かもしれません。

認証・認可の手段としてCognito使わない場合

よくAmplifyのサンプルや紹介でCognitoを利用したAuthの実装が簡単だというものを見たことがあるかと思います。確かに、Cognitoで認証する場合は、Cognitoの設定がCLIから簡単にできるだけでなく認証画面も簡単に作れます。また、前述のとおりAWSの認可の仕組みをそのままアプリケーションからも利用したい場合はAmplifyという選択はとてもいいと思います。

一方で、そもそも認証手段としてCognito以外を使いたいケースも多いのではないでしょうか。そしてIAMベースの認可が不要な場合。この場合はもちろんAmplifyは不要です。

そして、認証は別でやりたいけどIAMベースの認可はしたい。そんなときCognitoにはSAML連携やOIDC対応の外部プロバイダ、あとは主要なソーシャルログインプロバイダ(FacebookGoogleなど)と認証部分を連携させることができます。

でもAmplify CLIからこれらの設定がすべてサポートされているわけではないんですね。例えばSAMLやOIDCのプロバイダ、例えば認証にAuth0を使うといったフェデレーションの設定はAmplify CLIからはできないため結局、マネージメントコンソールからの作業が必要になります。
※ソーシャルログインのフェデレーションは設定できます

Server Side Rendering(SSR)の場合

まず、Amplify Consoleの話から。AmplifyがSSRに対応したといってもLibrary側の話であってAuthにおけるLocal Storage依存をやめたとかそういう話です。Amplify ConsoleでSSRもホストできるようになったというわけではないです。つまり、Amplify Consoleでは依然としてSSRを必要とするサイトはホスティングできない。

そしてLibrary側の話をすると、Next.jsとかを使ってSSRしたいときに普通に使えるよってことです。ただ、公式のドキュメントとかではデプロイをamplify pushではなくてServerles FrameworkのServerless Next.js Componentを使ってる。だったら別にAmplify要らないかなーと思ったけど、そこは結局前述のAWSのリソース使いたい場合とかと一緒ですね。

AWS WAF使いたい場合

これもAmplify Consoleの場合の話です。Amplify Consoleの静的サイトのホスティングは、コンテンツ配信にCDNであるCloudFrontを自動でセットアップしてくれます。だがしかし、ここで作られるCloudFrontのリソースはユーザには見えないのです。つまりサービス側が所有するリソースとして作られているのです。というわけで何らかの理由でCloudFrontと連携させる形でAWS WAFを使いたいとなっても現時点ではできない。あとはCloudFrontの細かい設定をしたい場合なども。

代わりにamplify publishを使えばユーザのリソースとしてCloudFrontとS3がセットアップされますが、AWS WAFを使う場合は別途設定が必要です。

Amplify CLIに対応していないバックエンドを利用したい場合

一応このような場合でも、Cloudformationのテンプレートを自分で用意してカスタムカテゴリとして登録するって方法があるにはあります。なので基本的にはAmplifyの機能を使いつつそこだけ自分で用意するってことができます。

でも、自分でCloudformationのテンプレート用意する時点でAmplifyの利点は失われているとも言えます。それを用意するならCDKとか使ったほうが楽だなと僕なら思ってしまいます。もちろん、そのボリューム感見合いの話ではあるのですが。

AWS Amplifyがおすすめのケース

最後にAmplifyがおすすめのケースについても簡単にお話しておきます。基本的にはこれまでの話の裏返しなんですが、ここまで触れてこなかったパターンが1つあります。

それは、

フロントエンド開発者がAppSyncを使ってGraphQLでシンプルなアプリを開発する場合

です。このケースの場合はAmplify使うのを強くおすすめします。とても良い体験が得られると思います。

これに関してはいろんなところでサンプルやドキュメントがあるのでそちらを参照してください。

一方でシンプルと言っているのには理由があります。それはAmplifyからAppSyncを使う場合に利用できる@connectionディレクティブです。これを使うとDynamoDBにも関わらずRDBMSのようなリレーションを表現できます。実際にはリレーションを表現するためのリゾルバが自動で生成されるのと、多対多の場合もマッピングテーブルを用意して実現できます。なので、RDBMS感覚で複雑なリレーションを張ってしまうと…、はいお察しですね。

というわけであくまでもシンプルな構成、リレーション張るにしても感覚的には1階層くらいかなと思っています。繰り返しますが、餅は餅屋です。

まとめ

というわけでAWS Amplifyはドンピシャにはまるケースだととても簡単にフロントエンド側からバックエンドのプロビジョニングや設定も行えるのでそういう場合はおすすめです。

一方でこのようなEase of Developmentを実現する系のツールセットはあくまでもシンプルなものを手軽に素早く立ち上げるのには向いていますが、一歩そこからはみ出て凝ったことをしようと思うとそのメリットを享受できなくなることもしばしばあります。

特にAmplifyのようにビルディングブロックとして存在するバックエンドをWrapする形で実現しているものはその傾向が強いと思います(仕方がないとも思います)。

GraphQLの使い勝手と相まってプロトタイプ開発なんかだとほんといいと思うので時間があればぜひ試してみてください。あとはAWSリソースを直接触る場合も!

©Keisuke Nishitani, 2020   プライバシーポリシー