Open17
Amplify - Lambda Functionで外部RestAPIを叩いてGraphQLで返してみる
外部のRestAPIをLambda経由で加工してAppSyncのGraphQLで取得する試み。
Amplifyの初期設定は終わっているものとする。
とりあえずGraphQL APIを追加する。
名前はtestApi。
% amplify add api
? Select from one of the below mentioned services: GraphQL
? Here is the GraphQL API that we will create. Select a setting to edit or continue Continue
? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)
...
GraphQL schema compiled successfully.
...
✅ Successfully added resource viteproject locally
Lambda Functionを追加する。
名前はgetExternalApi。
% amplify add function
? Select which capability you want to add: Lambda function (serverless function)
? Provide an AWS Lambda function name: getExternalApi
? 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
? Do you want to edit the local lambda function now? No
Successfully added resource testFunc locally.
/amplify/backend/api/testApi/schema.graphql に以下を追加
// /amplify/backend/api/testApi/schema.graphql
type Query {
externalApi: AWSJSON @function(name: "getExternalApi-${env}")
}
/amplify/backend/function/getExternalApi/src 以下にtsconfig.jsonを追加
{
"compilerOptions": {
/* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
/* Interop Constraints */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
/* Completeness */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": [
"index.ts",
"src/**/*.ts"
],
"exclude": []
}
以下をインストール
% cd amplify/backend/function/getExternalApi/src
% yarn add axios @types/aws-lambda typescript
テンプレートのjsをtsに。
mv index.js index.ts
index.ts の書き換え
import axios from 'axios'
export const handler = async (event: any) => {
console.log(`EVENT: ${JSON.stringify(event)}`)
const response = await axios({
method:'GET',
url:'https://api.example.com/xxx', // 外部APIのエンドポイント
headers:{
'Content-Type': 'application/json',
'X-API-KEY': 'XXXXX' // テストだから直指定。実際は必ず環境変数に入れるようにすること。
}
})
return {
statusCode: response.data.statusCode,
body: response.data,
}
}
/package.json に以下を追記
"scripts": {
"lambdaUpdate": "cd amplify/backend/function/getExternalApi/src && npx tsc && cd -"
},
tsコンパイル
% yarn lambdaUpdate
yarn run v1.22.18
$ cd amplify/backend/function/getExternalApi/src && npx tsc && cd -
...
✨ Done in 0.73s.
Amplify push
% amplify push
...
? Are you sure you want to continue? Yes
...
フロントエンド(Vue3&Vuetify)から叩いてみる。
<script setup lang="ts">
import { externalApi } from '../graphql/queries'
const myJson = ref({})
const getExternalApi = async () => {
const response = await API.graphql({
query: externalApi
})
const result = JSON.parse(response.data.externalApi)
console.log(result)
myJson.value = result
}
</scirpt>
<template>
<v-container>
<h2 >External API Test</h2>
<v-btn block color="secondary" v-on:click="getExternalApi">Get</v-btn>
<p>{{ myJson }}</p>
</v-container>
</template>
OK
GraphQLから引数を受けられるようにする
schemaの更新
// /amplify/backend/api/testApi/schema.graphql
type Query {
externalApi(myId: String): AWSJSON @function(name: "getExternalApi-${env}")
}
functionの更新
// /amplify/backend/test-project/functions/getExternalApi/src/index.ts
import axios, { AxiosRequestConfig, AxiosRequestHeaders } from "axios"
export const handler = async (event: any) => {
console.log(`EVENT: ${JSON.stringify(event)}`)
const id = event.arguments.myId
const url = process.env.API_URL + "/" + id
const requestParam: AxiosRequestConfig = {
method: "GET",
url: url || "",
headers: {
'Content-Type': 'application/json',
'x-bintu-apikey': process.env.API_KEY || "",
},
}
const response = await axios(requestParam)
return {
statusCode: response.data.statusCode,
body: response.data,
}
}
frontendの更新
<script setup lang="ts">
import { externalApi } from '../graphql/queries'
const myJson = ref({})
const id = ref('xxx-xxx-xxx')
const getExternalApi = async () => {
const response = await API.graphql({
query: externalApi,
variables: {
myId: id.value
}
})
const result = JSON.parse(response.data.externalApi)
console.log(result)
myJson.value = result
}
</scirpt>
<template>
<v-container>
<h2 >External API Test</h2>
<v-text-field v-model="id" label="id"></v-text-field>
<v-btn block color="secondary" v-on:click="getExternalApi">Get</v-btn>
<p>{{ myJson }}</p>
</v-container>
</template>
OK
外部APIのAPIキーを環境変数に保持するようにする
functionの設定変更で、環境変数を入れる
% amplify update function
? Select the Lambda function you want to update getExternalApi
General information
- Name: getExternalApi
- Runtime: nodejs
Resource access permission
- test-project (Query)
Scheduled recurring invocation
- Not configured
Lambda layers
- Not configured
Environment variables:
- Not configured
Secrets configuration
- Not configured
? Which setting do you want to update? Environment variables configuration
? Enter the environment variable name: APIKEY
? Enter the environment variable value: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
? Select what you want to do with environment variables: I'm done
? Do you want to edit the local lambda function now? No
Lambda内でprocess.env使おうとしたら、なんか型エラーで怒られたので、色々直していく
// /amplify/backend/test-project/functions/getExternalApi/src/index.ts
import axios, { AxiosRequestConfig, AxiosRequestHeaders } from "axios"
export const handler = async (event: any) => {
console.log(`EVENT: ${JSON.stringify(event)}`)
const requestParam: AxiosRequestConfig = {
method: "GET",
url: process.env.API_URL || "",
headers: {
'Content-Type': 'application/json',
'x-bintu-apikey': process.env.API_KEY || "",
},
}
const response = await axios(requestParam)
return {
statusCode: response.data.statusCode,
body: response.data,
}
}
OK