作りたいもの
CDKでつくるMutation, Query, Subscriptionをするだけのできるだけ小さいサンプル2
認証をLambdaでする
完成品 https://github.com/tky/app-sync-with-lambda-auth-example
注意点
- subscription使うためにはschemaはcodeで定義
- aws-cdk/aws-appsync-alphaは将来変更が入るかも
実装
importから
import { Duration, Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import { Table, AttributeType } from "aws-cdk-lib/aws-dynamodb";
import {
AuthorizationType,
Directive,
GraphqlApi,
Field,
GraphqlType,
InputType,
MappingTemplate,
ObjectType,
PrimaryKey,
Values,
ResolvableField,
Schema,
} from "@aws-cdk/aws-appsync-alpha";
import { RemovalPolicy } from "aws-cdk-lib";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
簡単なschema
const typeUser = new ObjectType("User", {
definition: {
id: GraphqlType.string({ isRequired: true }),
name: GraphqlType.string({ isRequired: true }),
age: GraphqlType.int({ isRequired: false }),
},
});
const typeUserInput = new InputType("UserInput", {
definition: {
name: GraphqlType.string({ isRequired: true }),
age: GraphqlType.int({ isRequired: false }),
},
});
const schema = new Schema();
schema.addType(typeUser);
schema.addType(typeUserInput);
認証用のlambda
NodejsFunctionはこの書き方だと、{stackのファイル名}.{NodejsFunctionのid}.tsというファイルを探しに行きます。
cdk-stack.tsでhandlerというidにしたのでこのcdk-stack.tsと同じディレクトリにあるcdk-stack.handler.tsが必要です。
id変えたりstackのファイル名を変更する場合は注意が必要
const handler = new NodejsFunction(this, "handler", {
functionName: "app-sync-with-lambda-auth-hander",
});
API。認証をLambaにする
const api = new GraphqlApi(this, "api", {
name: "app-sync-with-lambda-auth-example-api",
schema,
authorizationConfig: {
defaultAuthorization: {
authorizationType: AuthorizationType.LAMBDA,
lambdaAuthorizerConfig: {
handler,
resultsCacheTtl: Duration.seconds(1),
},
},
},
xrayEnabled: false,
});
dynamodb
const table = new Table(this, "table", {
tableName: "app-sync-with-lambda-auth-example-table",
partitionKey: {
name: "id",
type: AttributeType.STRING,
},
removalPolicy: RemovalPolicy.DESTROY,
});
const dataSource = api.addDynamoDbDataSource("data_source", table);
Query
schema.addQuery(
"getUser",
new ResolvableField({
returnType: typeUser.attribute(),
args: {
id: GraphqlType.id({ isRequired: true }),
},
dataSource,
requestMappingTemplate: MappingTemplate.dynamoDbGetItem("id", "id"),
responseMappingTemplate: MappingTemplate.dynamoDbResultItem(),
})
);
Mutation
schema.addMutation(
"addUser",
new ResolvableField({
returnType: typeUser.attribute(),
args: {
id: GraphqlType.string({ isRequired: true }),
input: typeUserInput.attribute({ isRequired: true }),
},
dataSource,
requestMappingTemplate: MappingTemplate.dynamoDbPutItem(
PrimaryKey.partition("id").is("id"),
Values.projecting("input")
),
responseMappingTemplate: MappingTemplate.dynamoDbResultItem(),
})
);
Subscription
schema.addSubscription(
"updatedUser",
new Field({
returnType: typeUser.attribute(),
args: { id: GraphqlType.id({ isRequired: true }) },
directives: [Directive.subscribe("addUser")],
})
);
実行
API認証の場合は-H "x-api-key:${API_KEY}"
が必要でしたが今回はlambda認証なので代わりに-H "Authorization:${KEY}"
が必要です
とりあえずABCにしてあります
export QUERY='
mutation AddUser {
addUser(id: "user1", input: {age: 22, name: "first user"}) {
age
id
name
}
}
'
gq ${API_ENDPOINT} -H "Authorization:ABC" -q "${QUERY}"
Executing query... done
{
"data": {
"addUser": {
"age": 22,
"id": "user1",
"name": "first user"
}
}
}
もちろん他の値だと認証失敗
$ gq ${API_ENDPOINT} -H "Authorization:XYZ" -q "${QUERY}"
Executing query... error
Error: {
errors: [
{
errorType: 'UnauthorizedException',
message: 'You are not authorized to make this call.'
}
]
}
lambda
exports.handler = async (event: any) => {
console.log(JSON.stringify(event));
const isAuthorized = event.authorizationToken == "ABC";
const response = {
isAuthorized,
};
console.log(JSON.stringify(response));
return response;
};
hotswapつけてwatchするとlambda変更してすぐデプロイしてくれて便利です。
ついでにconsoleにログも出してくれます。
$cdk watch --hotswap