ちょっとしたデモ用のシステムを作っていてLambdaからAppSyncを叩いてみたメモ。
AppSyncはCognitoのUserPoolで認証を設定している。
LambdaのハンドラではCognitoの認証処理を行い、認証トークンを利用してAppSyncにアクセスする。
Lambdaのハンドラーは次のような感じで実装する。
handler.ts
import { AuthenticationDetails, CognitoUser, CognitoUserPool } from 'amazon-cognito-identity-js';
import { Handler } from 'aws-lambda';
import gql from 'graphql-tag';
import AWSAppSyncClient from 'aws-appsync';
import {AUTH_TYPE} from 'aws-appsync/lib/link/auth-link';
// tslint:disable-next-line:no-var-requires
require('isomorphic-fetch');
export const handler: Handler = async (event, context, callback) => {
const body = JSON.parse(event.body);
// CognitoのUserPoolに登録したユーザのログイン情報
const authenticationData = {
Password: process.env.PASSWORD,
Username: process.env.USERNAME,
};
const authenticationDetails = new AuthenticationDetails(authenticationData);
const poolData = {
ClientId: process.env.COGNITO_CLIENT_ID,
UserPoolId: process.env.COGNITO_USER_POOL_ID,
};
const userPool = new CognitoUserPool(poolData);
const userData = {
Pool: userPool,
Username: process.env.USERNAME,
};
const cognitoUser = new CognitoUser(userData);
// AppSyncを叩くために認証トークンを取得する。
// コールバック関数を渡すタイプの非同期処理になっているのでPromiseでくるんでAsync/Awaitで使いやすくする。
const authenticateUser = async (): Promise<string> => {
return new Promise((resolve, reject) => {
cognitoUser.authenticateUser(authenticationDetails, {
newPasswordRequired: (userAttributes, requiredAttributes) => {
const err = new Error('newPasswordRequired');
reject(err);
},
onFailure: (err) => {
reject(err);
},
onSuccess: (result) => {
const idToken = result.getIdToken().getJwtToken();
resolve(idToken);
},
});
});
};
const accessToken: string = await authenticateUser();
// 以降は取得したトークンを使ってAppsyncにアクセスするところ。
// AppSyncのSDKはPromiseに対応した実装になっているので使いやすい。
const appsyncOpts = {
auth: {
jwtToken: accessToken,
type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS,
},
disableOffline: true,
region: process.env.APPSYNC_REGION,
url: process.env.APPSYNC_ENDPOINT,
};
let response: {[key: string]: string|number};
try {
const appSyncClient = new AWSAppSyncClient(appsyncOpts);
// Mutationのリクエストを送信する
const {data} = await this.client.mutate({
mutation: gql(mutations.someMutation),
variables: {input},
});
const mutatedObj = data.someMutation;
response = {
body: JSON.stringify({ result: 'SUCCESS', mutatedObj }),
statusCode: 200,
};
} catch (error) {
response = {
body: JSON.stringify({ result: 'ERROR', name: error.name, message: error.message}),
statusCode: 500,
};
}
callback(null, response);
};
上記の例はMutationの例だけど、Queryの場合はappSyncClientがリクエストを送信する部分が次の様になるだけ。
const {data} = await appSyncClient.query({
fetchPolicy: 'network-only',
query: gql(queries.getObjectById),
variables: {id},
});
const queriedObject = data.getObjectById;