この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
吉川です。
早速ですが、AppSync+Lambdaリゾルバにおいて、(VTLではなく)Lambda関数からAppSync経由でクライアントへ errors
を返すにはどのようなコードを書けば良いのかについて調べたので共有します。
結論から言うと、 callback('Error Message.')
もしくは throw new Error('Error Message.')
どちらかのパターンを使うと良さそうでした。
環境
- node 16.13.0
- typescript 3.9.7
- aws-cdk-lib 2.20.0
- @aws-cdk/aws-appsync-alpha 2.20.0-alpha.0
- constructs 10.0.115
前提
CDKコード
lib/appsync-stack.ts
import { Construct } from 'constructs'
import * as cdk from 'aws-cdk-lib'
import * as appsync from '@aws-cdk/aws-appsync-alpha'
import * as lambdaNodejs from 'aws-cdk-lib/aws-lambda-nodejs'
export class AppSyncStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props)
/**
* Backend
*/
// AppSync API
const api = new appsync.GraphqlApi(this, 'myAppsyncApi', {
name: 'myAppsyncApi',
schema: appsync.Schema.fromAsset('./schema.graphql'),
authorizationConfig: {
defaultAuthorization: {
authorizationType: appsync.AuthorizationType.API_KEY,
},
},
})
// Lambda関数
const userFn = new lambdaNodejs.NodejsFunction(this, 'userFn', {
entry: 'lambda-handler/find-user-handler.ts',
})
// Lambda関数をDataSourceとしてAppSyncAPIと紐付ける
const userDs = api.addLambdaDataSource('userDs', userFn)
// schema.graphqlで定義した中のどの操作とマッピングするかを指定
userDs.createResolver({
typeName: 'Query',
fieldName: 'user',
})
}
}
スキーマファイル
schema.gql
type User {
id: String!
name: String!
}
type Query {
user: User!
}
投げるクエリ
以下のクエリをAppSyncマネジメントコンソールで投げて検証します。
query MyQuery {
user {
id
name
}
}
Lambda Resolverのエラーハンドリングパターンを色々試してみる
では、確認したパターンを紹介したいと思います。
callback()に文字列を渡す
callback()
関数にメッセージを渡すことでクライアントにエラーを返すことができます。
find-user-handler.ts
import { AppSyncResolverEvent, Callback, Context } from 'aws-lambda'
export const handler = async (
event: AppSyncResolverEvent<{}, {}>,
_: Context,
callback: Callback
) => {
console.log(JSON.stringify({ event }))
callback('Example error message.')
}
レスポンス
{
"data": null,
"errors": [
{
"path": [
"user"
],
"data": null,
"errorType": "string",
"errorInfo": null,
"locations": [
{
"line": 2,
"column": 3,
"sourceName": null
}
],
"message": "Example error message."
}
]
}
Errorをthrowする
Error
を throw
することでクライアントにエラーを返すことができます。
find-user-handler.ts
import { AppSyncResolverEvent, Callback, Context } from 'aws-lambda'
export const handler = async (event: AppSyncResolverEvent<{}, {}>) => {
console.log(JSON.stringify({ event }))
throw new Error('Example error message.')
}
レスポンス
{
"data": null,
"errors": [
{
"path": [
"user"
],
"data": null,
"errorType": "Error",
"errorInfo": null,
"locations": [
{
"line": 2,
"column": 3,
"sourceName": null
}
],
"message": "Example error message."
}
]
}
callback()にErrorを渡す
callback()
関数に Error
を渡すことでもクライアントにエラーを返すことができます。
import { AppSyncResolverEvent, Callback, Context } from 'aws-lambda'
class CustomError extends Error {
constructor(message: string) {
super(message)
this.name = 'CustomError'
}
}
export const handler = async (
event: AppSyncResolverEvent<{}, {}>,
_: Context,
callback: Callback
) => {
console.log(JSON.stringify({ event }))
callback(new Error('Example error message.'))
}
レスポンス
{
"data": null,
"errors": [
{
"path": [
"user"
],
"data": null,
"errorType": "Error",
"errorInfo": null,
"locations": [
{
"line": 2,
"column": 3,
"sourceName": null
}
],
"message": "Example error message."
}
]
}
カスタムErrorをthrowする
Error
を継承したカスタム Error
も throw
でエラーを返せます。
find-user-handler.ts
import { AppSyncResolverEvent, Callback, Context } from 'aws-lambda'
class CustomError extends Error {
constructor(message: string) {
super(message)
this.name = 'CustomError'
}
}
export const handler = async (event: AppSyncResolverEvent<{}, {}>) => {
console.log(JSON.stringify({ event }))
throw new CustomError('Custom error message.')
}
レスポンス
{
"data": null,
"errors": [
{
"path": [
"user"
],
"data": null,
"errorType": "CustomError",
"errorInfo": null,
"locations": [
{
"line": 2,
"column": 3,
"sourceName": null
}
],
"message": "Custom error message."
}
]
}
this.name = 'CustomError'
を記述しないと errorType
はデフォルトの Error
のままだったのでご注意ください。
なお、割愛しますが「 callback()
にカスタムErrorを渡す」パターンも同じように使うことができました。
[NG] 文字列をreturnする
callback()に文字列を渡すパターン
に準ずるかと思いましたが、こちらはできないようでした。
find-user-handler.ts
import { AppSyncResolverEvent, Callback, Context } from 'aws-lambda'
export const handler = async (event: AppSyncResolverEvent<{}, {}>) => {
console.log(JSON.stringify({ event }))
return 'Example error message.'
}
レスポンス
{
"data": null,
"errors": [
{
"path": [
"user",
"id"
],
"locations": null,
"message": "Cannot return null for non-nullable type: 'String' within parent 'User' (/user/id)"
},
{
"path": [
"user",
"name"
],
"locations": null,
"message": "Cannot return null for non-nullable type: 'String' within parent 'User' (/user/name)"
}
]
}
[NG] Errorをreturnする
こちらも callback()にErrorを渡すパターン
に準ずるかと思いましたが、できないようでした。
find-user-handler.ts
import { AppSyncResolverEvent, Callback, Context } from 'aws-lambda'
export const handler = async (event: AppSyncResolverEvent<{}, {}>) => {
console.log(JSON.stringify({ event }))
return new Error('Example error message.')
}
レスポンス
{
"data": null,
"errors": [
{
"path": [
"user",
"id"
],
"locations": null,
"message": "Cannot return null for non-nullable type: 'String' within parent 'User' (/user/id)"
},
{
"path": [
"user",
"name"
],
"locations": null,
"message": "Cannot return null for non-nullable type: 'String' within parent 'User' (/user/name)"
}
]
}
以上、参考になれば幸いです。