概要
AWS Amplify Advent Calendar 2019、19日目はAWS Amplifyの新機能MockingでGraphQL API開発スピードを爆上げする方法について書いていきます!
Amplify Mockingとは
2019.08.07に発表されたAmplify CLIの新(というにはいささか時間が経ってしまった)機能です。$ amplify push
はAWS CloudFormationのスタックの参照と変更を行うため、それなりに時間がかかってしまいます。$ amplify mock
コマンドを使用すると、$ amplify push
でクラウドリソースに変更反映する前に、変更後の動作確認をローカル環境で行うことが可能です。
現在Mockingが提供されているCategoryは、以下の3つです。
-
api
(GraphQL): AWS AppSync + Amazon DynamoDB -
storage
(Content): S3 -
function
: AWS Lambda
storage
とfunction
のMockingについては参考資料の共有に留め、本記事ではAPI(GraphQL)のMockingについて詳しく見ていきます。
Amplify Mock Commands
$ amplify mock
$ amplify mock api
$ amplify mock storage
$ amplify mock function <functionname>
amplify mock
に続いてMockしたいCategoryを続けることでMockすることができます。function
は一つのアプリケーションに複数のfunction
を作成することができるため、Mockしたいfunction
を明示的に渡します。Categoryを指定せずamplify mock
を実行した場合は、api
とstorage
のMockが始まります。
想定読者
$ amplify add api
してAWS AppSyncいじってるけど、毎回amplify push
の時間待つのだるいなぁ、とお考えの悩めるあなたに捧げます。途中Reactが出てきますが、一切触らないのでReactの知識は必要ありません。
動作確認環境
- react 16.12.0
- @aws-amplify/cli 4.5.0
参考資料
いくつか参考にした資料を載せておきます。Mockingを試すだけであれば、一番下の公式ドキュメントが早いです。
- [Mocking and Testing Serverless APIs with AWS Amplify - AWS Online Tech Talks - YouTube] (https://www.youtube.com/watch?v=OxrHplxZ8BA)
- New – Local Mocking and Testing with the Amplify CLI | AWS News Blog
- Developing and testing GraphQL APIs, Storage and Functions with Amplify Framework Local Mocking features | AWS Mobile Blog
- https://aws-amplify.github.io/docs/cli-toolchain/quickstart?sdk=js#mocking-and-testing
- https://aws-amplify.github.io/docs/cli-toolchain/usage?sdk=js#mocking-and-testing
検証用アプリケーションの準備
React App
本手順ではReactで進めますが、一切コードをいじらないので他のフレームワーク(Vue, Angular,Ionic)でアプリを作っていただいても大丈夫です。
$ npx create-react-app amplify-react
$ cd amplify-react
$ npm start
ブラウザが立ち上がり、おなじみのスタートページが現れます。
Amplifyの初期設定
amplify init
でAmplifyの初期設定を行います。
amplify configure
は一度実行している想定です。(amplify configure
がまだの方はコチラ)
${profile name}にはご自身が使用されているAmplify用のAWS Profile名を入力してください。
$ amplify init
? Enter a name for the project amplify-react
? Enter a name for the environment mocktest
? Choose your default editor: Vim (via Terminal, Mac OS only)
? 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 ${profile name}
GraphQL API作成
$ amplify add api
でMockingの検証に使用するBackendを設定していきましょう。
ポイントとしては一度API KEYでセットアップした上で、追加でAmazon Cognito User PoolとAWS IAMを利用した認証を追加しています。これは後ほど@auth
を利用した際のMockingを行うためです。画像を参考に設定してみてください。
準備完了です!Mockingを実際に使ってみましょう。
API Mocking
API Mockingを試してみよう!
先ほどadd api
したAppSyncのschema.graphql
を編集しましょう。
type Todo
@model
@key(fields: ["id"])
@auth(rules: [
{allow: owner, provider: userPools, operations: [create, read, update, delete]},
{allow: private, provider: userPools, operations: [read]},
{allow: public, provider: apiKey,operations: [read]},
])
{
id: ID!
name: String!
owner: String!
description: String
updatedAt: AWSDatetime
createdAt: AWSDatetime
}
@auth
についての解説は拙著Amplify CLI GraphQL TransformとディレクティブでAppSync+DynamoDBをいじってみよう!(@model @auth, @key) - Qiitaをご覧ください。上記のschema.graphql
における@auth
は、以下の認可を実現します。
- Cognito User Poolで認証したユーザーに次のアクションを許可
- Todoのcreate
- 自身が作成したアイテムのread, update, delete
- 他の人が作成したアイテムのread
- AppSyncのAPI_KEYで認証したユーザーにはreadのみを許可
ではこの設定をクラウドのリソースに反映する$ amplify push
...の前に!$ amplify mock api
してみましょう。
$ amplify mock api
Failed to start API Mock endpoint Error: Type "AWSDatetime" not found in document.
AWSDatetime
型なんて見つからないよ、というエラーが表示されました。AppSyncのスカラー型によれば、正しくはAWSDateTime
です。うっかり間違えてしまいました。schema.graphql
を編集しましょう。
type Todo
@model
@key(fields: ["id"])
@auth(rules: [
{allow: owner, provider: userPools, operations: [create, read, update, delete]},
{allow: private, provider: userPools, operations: [read]},
{allow: public, provider: iam, operations: [read]},
{allow: public, provider: apiKey,operations: [read]},
])
{
id: ID!
name: String!
owner: String!
description: String
updatedAt: AWSDateTime
createdAt: AWSDateTime
}
$ amplify mock api
を実行したままであれば、変更を検知して再読み込みしてくれます。
今回はコンパイルが通りました!こうした細かな間違いを$ amplify push
をせずに試せるのは嬉しいですね。
フロントエンドからGraphQLでクエリするためのコードを自動生成するため、いくつか聞かれます。全てデフォルトの選択肢で大丈夫です。
本来であればMock用のAPIエンドポイントが表示されるのですが、Error後に上記の設定を行うとAPIエンドポイントが表示されないようです。一度Ctrl+C
で実行を止め、再度$ amplify mock api
しましょう。
http://192.168.1.6:20002
でGraphQLのMockサーバーが立ち上がりました!
192.168.1.6
の部分は検証環境のネットワークでご自身のPC(またはサーバーなど)に割り当てられたローカルIPアドレスになります。
API Mockingで作成されるもの
API Mockingが動かせたところで、$ amplify mock api
した時に何が作られているのか確認して、全体感を抑えておきましょう。
New – Local Mocking and Testing with the Amplify CLI | AWS News Blogによれば、$ amplify mock api
によって以下のリソースが作成されます。
-
the GraphQL transformations required by your API
-
DynamoDB Local to manage your API data locally
-
the Amplify GraphQL Explorer, based on the open source OneGraph graphiql-explorer plugin
-
GraphQL transformatinos
-
schema.graphql
からGraphQLで使用されるより詳細なschema、resolver、およびフロントエンドで使用するコードを生成
-
-
- SQLiteのDBをDynamoDB風のインタフェースでラップしたもので、Amplify GraphQL ExplorerのDBとして使用
- SQLiteなのでSQLiteが読めるプラグインをいれて自由に閲覧・編集可能
-
Amplify GraphQL Explorer
- OSSのOneGraph graphiql-explorer pluginをベースに開発されたGraphiQL(GraphQL IDEとも)プラグイン
- HTTPによるクエリを受け付けるGraphQLエンドポイントと、クエリを手軽に試せるGUIを提供
紹介されていませんが、地味に便利なのがaws-exports
をMockingの間だけlocalのMock API Endpointを指すように変更してくれる機能です。これについても後ほど確認します。
Amplify GraphQL Explorer
前項で立ち上がったエンドポイントにアクセスしてみましょう。
http://192.168.1.6:20002
Amplify GraphQL Explorerが立ち上がっています。いくつかアイテムを作成しましょう。
-
- ADD NEW MUTATIONをクリック
- createTodoをクリック
- 紫文字のinputフィールドのうち、必須である
id, name, owner
を適当に埋めましょう(必須フィールドにはid*
のように*
がついています) - 返り値として欲しいフィールドにチェックを入れます(今回は全て)
このように、GraphiQLのサポートのもと、非常に簡単にmutation
を書くことができました。それでは実際に上部の▶ をクリックして実行してみましょう。
右側に実行結果が表示されます。エラーがでました。メッセージを読むとcreateTodo
にアクセスする権限がありませんと表示されます。
schema.graphql
で書いた内容を思い出してみましょう。
- Cognito User Poolで認証したユーザーに次のアクションを許可
- Todoのcreate
- 自身が作成したアイテムのread, update, delete
- 他の人が作成したアイテムのread
- IAMで認証したユーザーと、AppSyncのAPI_KEYで認証したユーザーにはreadのみを許可
右上を見ると、Use: API Key
と表示されており、Amplify GraphQL Explorerがクエリを発行する際、認証情報としてAPI_KEYを使っていることがわかります。API_KEYで認証したユーザーにはread
権限しか与えていないため弾かれたのですね。Amplify GraphQL Explorerがちゃんと@auth
を再現して認可をしていることがわかります。
では、create
権限をもったCognito User Poolで認証したユーザーに切り替えてみましょう。
Use: API Key
をクリックし、Use: User Pool
に切り替えます。
続いて隣のUpdate Auth
をクリックし、Auth Optionsを開きましょう。
UsernameとEmailに適当な値を入力し、Generate Token
をクリックします。
UsernameはMutationのinputのowner
と一致する必要があることに注意してください。
この状態で再度Mutationを実行してみましょう。
無事Mutationすることができました!
続けて別のユーザーに切り替えてみます。再度Update Auth
をクリックしてユーザーの情報を書き換えましょう。
Generate Token後、先ほど他のユーザー作ったTodoにMutation(update)をしてみます。
失敗しますね、設定通りです。
最後にAPI_KEY認証に変え、listTodo
してみましょう。
API_KEY認証でread
できることが確認できました。
ローカルのReactアプリからMockされたEndpointを叩く
Amplify CLIでは、 $ amplify add {category}
して$ amplify push
すると、Amplify Framework(SDK)から作成したリソースを叩くために必要な情報をaws-exports.js
に吐き出してくれます。aws-exports.js
の中身を使ってAmplifyの初期設定を行うとリソース変更や追加をしてもコンフィグを書き換える必要がなくなり、非常に楽です。
例えばJavaScriptでは、次のようにAmplifyの設定を行います。
import awsmobile from './aws-exports';
import Amplify from 'aws-amplify';
Amplify.configure(awsmobile)
aws-exports.js
の中身をみてみましょう。
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
const awsmobile = {
"aws_project_region": "us-west-2"
};
export default awsmobile;
今回は一度も$ amplify push
していないため、リソースに関する記述が一切ありません。この状態で$ amplify mock api
するとどうなるのでしょうか。
$ amplify mock api
でAPI Mockingしたまま、aws-exports.js
を確認してみましょう。
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
const awsmobile = {
"aws_project_region": "us-west-2",
"aws_appsync_graphqlEndpoint": "http://10.221.93.66:20002/graphql",
"aws_appsync_region": "us-west-2",
"aws_appsync_authenticationType": "API_KEY",
"aws_appsync_apiKey": "da2-fakeApiId123456",
"aws_appsync_dangerously_connect_to_http_endpoint_for_testing": true
};
export default awsmobile;
API Mockingをしている間だけ、ローカルのGraphQL Endpointを指すようにaws-exports.js
を書き換えてくれるのです!便利!
ちなみにここではAPI_KEY認証を使っていますが、前述のAmplify GraphQL ExplorerのUpdate Auth
を行ってUse: User Pool
にしてもaws-exports.js
には反映されないようです。。。updateに期待しましょう。
ではAPI MockingをCtrl+C
で抜けてaws-exports.js
を確認してみます。
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
const awsmobile = {
"aws_project_region": "us-west-2"
};
export default awsmobile;
空っぽの状態に戻っていますね。
API Mocking Tips
API Mockingのちょっとした豆知識を紹介します。
API Mockingに対応しているディレクティブ
https://aws-amplify.github.io/docs/cli-toolchain/usage?sdk=js#api-mocking-setup によれば、$ amplify mock api
に対応しているディレクティブは執筆時点で次の5つです。@searchable
と@prediction
だけ対応していません。
- @auth
- @key
- @connection
- @versioned
- @function
DynamoDB Localに破壊的な変更を加える
注)以下で紹介するテクニックは裏技的なもので、今後アップデートにより必要なくなったり、そもそも別の方法があったりするかもしれないものです。(他に方法があればぜひ教えてください!)最新情報はドキュメントやGitHubの確認をお願いします。
開発していると、DynamoDBにPK,SKの変更を伴う破壊的な変更をしたくなる場合があります。本番環境であればGSI(グローバルセカンダリインデックス)の追加や、メンテナンスウィンドウを設けてのTable移行になるかと思います。重ねての紹介で恐縮ですが、AmplifyでGSIを使ってみようという内容も前回のAmplify Advent Calendar記事で書いたのでよければご覧ください。
突如id
でなくname
フィールドでクエリしたい衝動に駆られました。schema.graphql
を次のように変更しましょう。
type Todo
@model
@key(fields: ["name"])
@auth(rules: [
{allow: owner, provider: userPools, operations: [create, read, update, delete]},
{allow: private, provider: userPools, operations: [read]},
{allow: public, provider: iam, operations: [read]},
{allow: public, provider: apiKey,operations: [read]},
])
{
id: ID!
name: String!
owner: String!
description: String
updatedAt: AWSDateTime
createdAt: AWSDateTime
}
$ amplify mock api
のログを見ると、普通に変更できていそうです。
GraphQL schema compiled successfully.
...(中略)...
Creating table DataStore locally
Creating table TodoTable locally
Running GraphQL codegen
✔ Generated GraphQL operations successfully and saved at src/graphql
Amplify GraphQL Exploererはホットリロードされないので、一度リロードしてからMutationを実行してみましょう。
Use User Pool
になっていることを確認してください。
DynamoDB:ValidationException
が発生しました。作成時のPK, SKのままのDynamoDB LocalにPK変換後のMutationを投げてしまったためです。(ちなみに$ amplify push
の場合、DynamoDBのPK,SKの更新を伴う変更は、CloudFormation実行時に弾かれます。)
こうした場合、クラウドリソースであれば一度変更したいtypeをまるっとコメントアウトして$ amplify push
してDynamoDB Tableを削除し、その後コメントアウトを解除して$ amplify push
することで再度作成するというテクニックがあります。API Mockingの場合にはSQLiteのファイルを削除するとよさそうです。
$ rm amplify/mock-data/dynamodb/fake_us-fake-1.db
$ amplify mock api
GraphQL schema compiled successfully.
Creating table DataStore locally
Creating table TodoTable locally
Running GraphQL codegen
✔ Generated GraphQL operations successfully and saved at src/graphql
AppSync Mock endpoint is running at http://10.221.93.17:20002
ログから、TodoTableが作成されたことがわかります。Amplify GraphQL Explorerを更新して、再度Mutationを実行してみましょう。
続いてQueryを実行します。
無事、新しいPKであるname
フィールドを使ってgetTodo
できました。
まとめ
- Mockingにより、クラウドリソースに変更反映する前に、変更後の動作確認をローカル環境で行うことが可能になります
- Mockingが提供されているCategoryはAPI(GraphQL)、Storage、Functionの三つ
- API Mockingが提供するのは次の四つです
- GraphQL transformations
- DynamoDB Local
- Amplify GraphQL Explorer
- aws-exports.jsの自動編集
Amplify Mockingによって開発スピードが大幅に向上した実感があります。細かい変更確認のために$ amplify push
していたあの頃には戻れそうにありません。
ぜひAPI Mockingだけでなく、Storage、FunctionのMockingについても触ってみてください!
AWS Amplify Advent Calendar、明日は @rtaguchi さんです!