これまで、以下の記事でAPIGatewayからKintone REST APIを呼んでみましたが、CloudFormationがAPIGatewayに対応したので、ここまでやったことをCloudFormationのtemplate化してみました。(swaggerは使ったこと無い )
注意
kintone REST APIは同時アクセス数がドメインごとに10と制限されています。
ドメインへの同時アクセス
・APIによる同時アクセス数はドメインごとに10が上限です。
実システムで利用する場合は、API Gatewayのスロットリング設定やエラーのリトライなどを考慮する必要が有ります。
注意ここまで
上記の記事でやったことの他にCORS対応もやってしまいます。
CORSについては、greenspaさんがわかりやすくまとめてくれています。
ソース
{
"AWSTemplateFormatVersion":"2010-09-09",
"Description":"Sample stack for Kintone Proxy",
"Parameters":{
"StageName":{
"Type":"String",
"MinLength":1,
"Default":"prod"
},
"KintoneSubdomain":{
"Type":"String",
"MinLength":1
},
"KintoneApiToken":{
"Type":"String",
"MinLength":1
},
"KintoneAppId":{
"Type":"String",
"MinLength":1
},
"AccessControlAllowOrigin":{
"Type":"String",
"MinLength":1,
"Default":"*"
}
},
"Metadata":{
"AWS::CloudFormation::Interface":{
"ParameterGroups":[
{
"Label":{"default":"API Gateway configuration."},
"Parameters":["StageName"]
},
{
"Label":{"default":"Kintone configuration."},
"Parameters":["KintoneSubdomain","KintoneApiToken","KintoneAppId"]
}
]
}
},
"Resources":{
"RestApi":{
"Type" : "AWS::ApiGateway::RestApi",
"Properties" : {
"Description" : {"Fn::Join":["",["Create from ",{"Ref":"AWS::StackName"}]]},
"FailOnWarnings" : true,
"Name" : {"Fn::Join":["",[{"Ref":"AWS::StackName"},"-Api"]]}
}
},
"ApiMethodPOST":{
"Type" : "AWS::ApiGateway::Method",
"Properties" : {
"ResourceId" : {"Fn::GetAtt":["RestApi","RootResourceId"]},
"RestApiId":{"Ref":"RestApi"},
"HttpMethod" : "POST",
"AuthorizationType" : "NONE",
"ApiKeyRequired" : false,
"Integration" : {
"Type" : "HTTP",
"Uri" : "https://${stageVariables.subdomain}.cybozu.com/k/v1/record.json",
"IntegrationHttpMethod" : "POST",
"RequestParameters" : {
"integration.request.header.X-Cybozu-API-Token":"stageVariables.apiToken"
},
"RequestTemplates" : {
"application/json":{"Fn::Join":["",[
"{","\n",
" \"app\":\"${stageVariables.appId}\",","\n",
" \"record\":{","\n",
" \"item1\":{\"value\":$input.json('$.item1')},","\n",
" \"item2\":{\"value\":$input.json('$.item2')}","\n",
" }","\n",
"}"
]]}
},
"IntegrationResponses" : [
{
"StatusCode" : "200",
"ResponseParameters" : {
"method.response.header.Access-Control-Allow-Origin":
{"Fn::Join":["",[
"'",
{"Ref":"AccessControlAllowOrigin"},
"'"
]]}
},
"ResponseTemplates" : {
"application/json": ""
}
},
{
"StatusCode" : "400",
"SelectionPattern" : "[^2]\\d{2}",
"ResponseParameters" : {
"method.response.header.Access-Control-Allow-Origin":
{"Fn::Join":["",[
"'",
{"Ref":"AccessControlAllowOrigin"},
"'"
]]}
},
"ResponseTemplates" : {
"application/json": ""
}
}
]
},
"MethodResponses" : [
{
"StatusCode" : "200",
"ResponseParameters" : {
"method.response.header.Access-Control-Allow-Origin": false
}
},
{
"StatusCode" : "400",
"ResponseParameters" : {
"method.response.header.Access-Control-Allow-Origin": false
}
}
]
}
},
"ApiMethodOPTIONS":{
"Type" : "AWS::ApiGateway::Method",
"Properties" : {
"ResourceId" : {"Fn::GetAtt":["RestApi","RootResourceId"]},
"RestApiId":{"Ref":"RestApi"},
"HttpMethod" : "OPTIONS",
"AuthorizationType" : "NONE",
"ApiKeyRequired" : false,
"Integration" : {
"Type" : "MOCK",
"RequestTemplates" : {
"application/json":"{\"statusCode\":200}"
},
"IntegrationResponses" : [
{
"StatusCode" : "200",
"ResponseParameters" : {
"method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'",
"method.response.header.Access-Control-Allow-Methods": "'POST,OPTIONS'",
"method.response.header.Access-Control-Allow-Origin": {"Fn::Join":["",[
"'",
{"Ref":"AccessControlAllowOrigin"},
"'"
]]}
},
"ResponseTemplates" : {
"application/json":""
}
}
]
},
"MethodResponses" : [
{
"StatusCode" : "200",
"ResponseParameters" : {
"method.response.header.Access-Control-Allow-Headers": false,
"method.response.header.Access-Control-Allow-Methods": false,
"method.response.header.Access-Control-Allow-Origin": false
},
"ResponseModels" : {
"application/json": "Empty"
}
}
]
}
},
"ApiDeployment":{
"DependsOn":[
"ApiMethodPOST",
"ApiMethodOPTIONS"
],
"Type" : "AWS::ApiGateway::Deployment",
"Properties" : {
"RestApiId" : {"Ref":"RestApi"},
"StageName" : {"Ref":"StageName"},
"StageDescription":{
"Variables" : {
"subdomain":{"Ref":"KintoneSubdomain"},
"apiToken":{"Ref":"KintoneApiToken"},
"appId":{"Ref":"KintoneAppId"}
}
}
}
}
},
"Outputs":{
"RestApiEndpoint":{
"Value":{"Fn::Join":["",[
"https://",
{"Ref":"RestApi"},
".execute-api.",
{"Ref":"AWS::Region"},
".amazonaws.com/",
{"Ref":"StageName"},
"/"
]]}
}
}
}
解説
- CloudFormation StackのParameterでKintone関連の情報を渡すと、StageVariablesに設定します。
-
Metadata
の部分は、ManagementConsoleでのParameter入力時の見た目を制御しています。 - 今回の例ではAPI Keyも認可も行っていないのでプリフライトリクエストでの
Access-Control-Allow-Headers
に使われないヘッダが含まれています。 -
APIGatewayのHTTP ProxyでKintoneのREST APIを呼ぶ(1)でKitone側で日本語のフィールドコードがあると何か良くないことが起こるようなことを書きましたが、CloudFormationのtemplateで日本語をかけないので、
RequestTemplates
で詰みました。
ブラウザから実行
テスト用HTML
<html>
<head>
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script>
var settings = {
"async": true,
"crossDomain": true,
"url": "https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/",
"method": "POST",
"headers": {
"content-type": "application/json"
},
"processData": false,
"data": "{\n \"item1\":\"from Browser\",\n \"item2\":\"item2\"\n}"
}
$.ajax(settings).done(function (response) {
console.log(response);
});
</script>
</body>
</html>
実行結果(ChromeのDeveloperToolより)
OPTIONS (プリフライトリクエスト)
POST
結果
(Kintone側は省略)
、、といとも簡単にできてしまいました。
僕は、パラメータも渡せてDeploy・ApiKeyに対応しているCloudFormationがSwaggerよりも好きです!(宣言)
では!