AWS Amplify フレームワークの使い方Part16〜GraphQL Transform @function編〜

# はじめに
気づいたら追加されていて存在だけは知っていましたが、ずっと手を出していなかった＠functionについてご紹介！

この機能、控えめに言って、最高です。

# なにができるのか
AmplifyのAPIを使ってLambda関数の実行ができます。わざわざ自分でAPIGatewayを作成してLambdaに紐付けを行う必要はありません。

# 定義
至ってシンプルな定義です。

```
directive @function(name: String!, region: String) on FIELD_DEFINITION
```
## name
呼び出したいLambda関数名を記載します。

## region
呼び出したいLamabda関数のリージョンを記載します。(省略可)

# 基本的な使い方
使い方は簡単です。

Lambda関数を準備し、schemaファイルにQueryとMutationを宣言して、amplify add functionで作成したLambdaを紐付けるだけです！

## Lambda関数準備
まずは呼び出したいLambda関数を準備してください。

```javascript:echoFunction1/index.js
exports.handler = async (event) => {
  return 'こんにちは！'
}

```


```javascript:echoFunction2/index.js
exports.handler = async (event) => {
  const name = event.arguments.name
  return `${name}さん、こんにちは！`
}

```


```javascript:echoFunction3/index.js
exports.handler = async (event) => {
  const name = event.arguments.msg.name
  const comment = event.arguments.msg.comment
  return {
    timestamp: new Date()
    text: `${name}さん、こんにちは！${comment}`
  }
}

```

```javascript:echoFunction4/index.js
exports.handler = async (event) => {
  const postTitle = event.arguments.postAndTagInfo.postTitle
  const postText = event.arguments.postAndTagInfo.postText
  const tagTitle = event.arguments.postAndTagInfo.tagTitle

  // １）送られてきたデータを整形処理を記載
  // ２）Postへの書き込み処理を記載
  // ３）Tagの書き込み処理を記載
  // ４）スキーマで宣言した返り値を記載
  return {}
}

```

## Query(データ取得系関数用)
基本構成は以下の4つです。

1. 関数名(echo1)
2. 引数の型定義((msg: String))
3. 返り値の定義(String)
4. Lambda関数紐付け(＠function(name: "echoFunction-${env}"))

```schema.graphql
type Query {
  // 1) 引数なし
  echo1: String @function(name: "echoFunction1-${env}")
  // 2) 引数あり
  echo2(name: String): String @function(name: "echoFunction2-${env}")
  // 3) 引数あり、オブジェクト
  echo3(msg: Message): ReplyMessage @function(name: "echoFunction3-${env}")
}

// 引数用オブジェクト
input Message {
  name: String
  comment: String
}

// 返り値用オブジェクト
type ReplyMessage {
  timestamp: String
  text: String
}
```

```javascript:index.js

import { API, graphqlOperation} from 'aws-amplify'
import * as gqlQueries from '../graphql/queries'

// 1) 引数なし
const result = await API.graphql(
  graphqlOperation(gqlQueries.echo1)
)
console.log(result.data.echo1) // こんにちは!

// 2) 引数あり
const result = await API.graphql(
  graphqlOperation(gqlQueries.echo2, { name : '太郎' })
)
console.log(result.data.echo2) // 太郎さん、こんにちは！

// 3) 引数あり、オブジェクト
const result = await API.graphql(
  graphqlOperation(gqlQueries.echo3, {
    msg: {
       name:  '太郎'
       comment:  '頑張ろう！！'
    }
  })
)
console.log(result.data.echo3) // { timestamp: '日時', text: '太郎さん、こんにちは！頑張ろう!!' }
```
## Mutation(データ更新系関数用)
Queryと基本構成は全く同じです。

1. 関数名(createPostAndTag)
2. 引数の型定義((postAndTagInfo: PostAndTagInfo))
3. 返り値の定義(Post)
4. 関数紐付け(＠function(name: "createPostAndTag-${env}"))

```schema.graphql
type Mutation {
  createPostAndTag(postAndTagInfo: PostAndTagInfo): Post @function(name: "createPostAndTag-${env}")
}

// 引数用オブジェクト
input PostAndTagInfo {
  postTitle: String
  postText: String
  tagTitle: String
}

// 返り値用オブジェクト
type Post {
  id: ID!
  title: String
  text: String
  createdAt: AWSDateTime
  updatedAt: AWSDateTime
}
```

```javascript:index.js

import { API, graphqlOperation} from 'aws-amplify'
import * as gqlMutations from '../graphql/mutations'

const result = await API.graphql(
  graphqlOperation(gqlMutations.createPostAndTag, {
    postTitle: '記事名',
    postText: '本文',
    tagTitle: 'タグ名'
  })
)
return result.data.createPostAndTag // POST情報
```

# その他機能
## 関数名の指定
指定する関数名に`${env}‘を記載すれば、amplifyの環境ごとのLambda関数を呼び出せます。Amplify経由で作成したLambda関数を呼び出す場合は、基本的に記載する必要があります。

```
type Query {
  echo(msg: String): String @function(name: "echofunction-${env}")
}
```
## 他リージョンの関数呼び出し
リージョン指定もできるので、他リージョンの呼び出しも可能です。現時点では、本元のAWSAppSyncではできる他のAWSアカウントのLambda関数の呼び出しはできないようです。

## チェーン機能
この機能が素晴らしいと思っています。

＠functionは複数つなげることができるようになっています。
始めの＠functionの完了後、その結果を次の＠functionが受け取って実行されます。

```
type Mutation {
  doSomeWork(msg: String): String @function(name: "worker-function") @function(name: "audit-function")
}
```

例えば、1つ目の関数で特定の条件の認証を行い、2つ目の関数で認証OKな場合のみ特定の関数を実行とかが簡単にできてしまいますね。

## lambdaに渡されるイベント情報
以下のようなイベントがLambdaには渡されますので、この情報を想定してLambda関数を作成します。

typeName :  オブジェクトのタイプ名(QueryかMutation)
fieldName：フィールド名(echo)
arguments：引数
identity：リクエストユーザーの認証情報(ユーザー名、メールアドレス等)
request：ヘッダー情報(authorizationのトークン情報等)
source,prev：どちらかにfunctionをチェーンしたときに前functionの返り値(未検証)


# はまりポイント解説
はまりポイント解説しようと思いましたが、今のところ珍しく何もはまっていません。

見つかったら追記していきます。

# おわりに
Amplifyって本当に気づいたら素晴らしい機能が追加されていることって多いですね。
知らなかったことによる無駄な労力を発生させてしまう確率がどのサービスよりも多い気がしますので、Amplifyの更新情報チェックは重要です。

# 参考
[Configure Lambda resolvers (公式doc)](https://docs.amplify.aws/cli/graphql-transformer/function)
[TIMELINE機能: @FUNCTION(公式workshop)](https://amplify-sns.workshop.aws/50_follow_timeline/30_function_directive.html)