🕌

Amplify Functions 入門編 その1

2022/06/14に公開

概要

  • サーバレスコンピューティングをAmplify CLIを使って作成できる
  • Amplifyで作成したリソースへのアクセス権限の管理が楽
  • Libraryからの呼び出しとしてはGraphQL又はREST API
  • DynamoDB テーブル内のデータ変更に対応するアプリケーションやバッチ処理を作成できる

Amplify Functionsを使って共同編集ができる仕組みが作れないものかと軽い気持ちで触ってみました。
途中これAmplifyにこだわる必要あるのかと心折れそうになりました。
最終的には面倒な権限設定関係や環境構築をAmplifyがやってくれているものということに気付くことができました。
この記事を書いているときのcliのバージョンは7.6.22です。

なぜAmplify Functionsを使うのか

  • Amplifyで作ったリソースにアクセスする Storage(S3),DynamoDB(api)
  • フロントエンドとバックエンドの管理を共有できる
  • Amplifyからはブラックボックスのリソースにアクセスする(CDK)

Amplifyの良いところはバックエンドのことを意識せずにmBaaS的な環境を手に入れることができることです。
矛盾しますがAmplifyを知れば知るほどバックエンドを意識するようになります。

amplify add function

functions ≒ Lambdaです。
注意すべきところとしてはadd function単体ではAmplifyからの呼び出し手段を構築しません。
つまりバックエンドのAmplify CLIとフロントエンドは全く別であることを知る必要があります。

amplify add function

次に対話形式で聞かれるので以下のように選択します。

? Select which capability you want to add: Lambda function (serverless function)
? Provide an AWS Lambda function name: helloWorld
? Choose the runtime that you want to use: NodeJS
? Choose the function template that you want to use: Hello World

Available advanced settings:
- Resource access permissions
- Scheduled recurring invocation
- Lambda layers configuration
- Environment variables configuration
- Secret values configuration

? Do you want to configure advanced settings? No

以下のようなサンプルコードができます。

amplify/backend/function/helloWorld/src/index.js
/**
 * @type {import('@types/aws-lambda').APIGatewayProxyHandler}
 */
exports.handler = async (event) => {
    console.log(`EVENT: ${JSON.stringify(event)}`);
    return {
        statusCode: 200,
    //  Uncomment below to enable CORS requests
    //  headers: {
    //      "Access-Control-Allow-Origin": "*",
    //      "Access-Control-Allow-Headers": "*"
    //  }, 
        body: JSON.stringify('Hello from Lambda!'),
    };
};

呼び出すとステータスコードを200(数字)で返し、
Bodyをストリングで返すというコードになっています。
自分はここの返り値を変えて受け側(Lambda Resolver)を変えてなかったためにうまくデータの受け渡しができず、混乱しました。

Lambda Resolverを作成

GraphQL経由で呼び出す場合は、QueryかMutationとして定義します。
実はQueryかMutaitionの内容はFunctionとは関係性がないので、すべてQueryで定義したりMutationで定義することも可能です。
ですが一般的にはQueryはデータ取得。Mutationはデータ更新で分けたほうが良いでしょう。

schema.graphql
//戻り値用の型(helloWorldに合わせる)
type statusResult {
  statusCode: Int
  body: String
}
type Query {
  helloWorld:statusResult
  @function(name: "helloWorld-${env}")
  @auth(rules: [{ allow: private, provider: userPools }])
}

※schema.graphqlを更新したらamplify pushを忘れずに

amplify push

続いて呼び出し側のフロントエンドの例です

src/components/MyApi.vue
<script lang="ts" setup>
import { API, graphqlOperation } from 'aws-amplify'
import { GraphQLResult } from '@aws-amplify/api-graphql'
import { HelloWorldQuery } from '@/API'
import { helloWorld } from '@/graphql/queries'
const clickHello = async () => {
  const result = await API.graphql(graphqlOperation(helloWorld)) as GraphQLResult<HelloWorldQuery>
  console.log(result.data?.helloWorld?.body)
}
</script>

ちょっとした呼び出しに対して非常にいろいろ書かないといけないため、面倒に感じますが
Amplifyが@/API,@/graphql/queriesは自動生成してくれるため、慣れてくれるととても簡単で読みやすい内容です。

Next Step

  • それぞれの詳しい内容を掘り下げてみます。

Discussion