AWSメモ >

AWS API Gateway&LambdaをSwaggerで定義する

TODO: 書きかけ - 動作未確認


テーブル定義

aws dynamodb create-table  \
    --profile developper \
    --table-name Books \
    --attribute-definitions \
        AttributeName=id,AttributeType=S \
        AttributeName=isbn,AttributeType=S \
        AttributeName=title,AttributeType=S \
    --key-schema AttributeName=id,KeyType=HASH AttributeName=isbn,KeyType=RANGE \
    --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 \
    --global-secondary-indexes IndexName=title-index,
          KeySchema=[{AttributeName=title,KeyType=RANGE}],Projection={ProjectionType=KEYS_ONLY},
          ProvisionedThroughput={ReadCapacityUnits=1,WriteCapacityUnits=1}

Lambda関数作成

'use strict';

var crypto = require('crypto');
var AWS = require('aws-sdk');

var documentClient = new AWS.DynamoDB.DocumentClient();

const tableName = "Book";

const createResponse = (callback, statusCode, body) => {
    var res = {
        "statusCode": statusCode,
        "body": JSON.stringify(body)
    }
    callback(null, res);
}

exports.handler = (event, context, callback) => {
    var req = event.body;
    if (typeof(req) === "string") {
      req = JSON.parse(req);
    }
    var id = false;
    if (event.pathParameters){
        id = event.pathParameters.id || false;
    }
    switch(event.httpMethod){
        case "GET":
            if(id) {
                var params = {
                  TableName : tableName,
                  KeyConditionExpression: '#id = :id',
                  ExpressionAttributeNames:{ '#id': 'id'},
                  ExpressionAttributeValues:{':id': id }
                };
                documentClient.query(params, function(err, data) {
                   if (err) {
                        createResponse(callback, 500, { "msg": "Get Error!", "err": err, "params" : params });
                   } else {
                        var result = data;
                        if (data.Items) {
                          data = data.Items[0] || {};
                          var childCount = data.children ? data.children.length : 0;
                          result = { "data" : data , "message" : data.name + " has " + childCount + " children" }
                        }
                        createResponse(callback, 200, result);
                   }
                });
                return;  
            } else {
                var params = {
                  TableName : tableName
                };
                documentClient.scan(params, function(err, data) {
                   if (err) {
                        createResponse(callback, 500, { "msg": "List Error!", "err": err});
                   } else {
                        var result = data.Items || data;
                        createResponse(callback, 200, result);
                   }
                });
            }
            break;
        case "POST": 
            var newId = crypto.createHash('md5').update(new Date().getTime().toString()).digest('hex');
            var params = {
                TableName : tableName,
                Item: {
                    "id" : newId,
                    "isbn" : req.isbn,
                    "title" : req.title,
                    "price" : parseInt(req.price, 10)
                }
            };
            documentClient.put(params, function(err, data) {
                if (err) {
                    console.log(err);
                    createResponse(callback, 500, { "msg": "Create Error!", "err": err, "params": params, "req": req});
                } else {
                    createResponse(callback, 200, { "msg": "Create OK!", "id": newId });
                }
            });
            break;
        case "PUT": 
            var params = {
                TableName : tableName,
                Key: { "id" : id },
                ExpressionAttributeNames: {
                    "#isbn" : "isbn",
                    "#title" : "title",
                    "#price" : "price"
                },
                ExpressionAttributeValues: {
                    ":isbn" : req.isbn,
                    ":title" : req.title,
                    ":price" : parseInt(req.price,10)
                },
                UpdateExpression: "SET #isbn = :isbn, #title = :title, #price = :price"
            };
            documentClient.update(params, function(err, data) {
                if (err) {
                    createResponse(callback, 500, { "msg": "Update Error!", "err": err, "params": params });
                } else {
                    createResponse(callback, 200, { "msg": "Update OK!", "params": params});
                }
            });
            break;
        case "DELETE": 
            var params = {
                TableName : tableName,
                Key: { "id" : id }
            };
            documentClient.delete(params, function(err, data) {
                if (err) {
                    createResponse(callback, 500, { "msg": "Delete Error!", "err": err, "params" : params });
                } else {
                    createResponse(callback, 200, { "msg": "Delete OK!", "params": params });
                }
            });
            break;
        default:
            console.log("Error: unsupported HTTP method (" + event.httpMethod + ")");
            createResponse(callback, 501, { "msg": "Error: unsupported HTTP method (" + event.httpMethod + ")" } );
    }
}

Lambda 関数と統合されたサンプル API の Swagger 定義

TODO: とりあえず参考URLの内容をそのまま写経しただけ。ここから上記のLambda用に書き換えていく
{
  "swagger": "2.0",
  "info": {
    "version": "2017-04-20T04:08:08Z",
    "title": "LambdaGate"
  },
  "host": "xxxxxxxxxx.execute-api.us-east-1.amazonaws.com",
  "basePath": "/test",
  "schemes": [
    "https"
  ],
  "paths": {
    "/calc": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "operand2",
            "in": "query",
            "required": true,
            "type": "string"
          },
          {
            "name": "operator",
            "in": "query",
            "required": true,
            "type": "string"
          },
          {
            "name": "operand1",
            "in": "query",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            },
            "headers": {
              "operand_1": {
                "type": "string"
              },
              "operand_2": {
                "type": "string"
              },
              "operator": {
                "type": "string"
              }
            }
          }
        },
        "x-amazon-apigateway-request-validator": "Validate query string parameters and headers",
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "default": {
              "statusCode": "200",
              "responseParameters": {
                "method.response.header.operator": "integration.response.body.op",
                "method.response.header.operand_2": "integration.response.body.b",
                "method.response.header.operand_1": "integration.response.body.a"
              },
              "responseTemplates": {
                "application/json": "#set($res = $input.path('$'))\n{\n    \"result\": \"$res.a, $res.b, $res.op => $res.c\",\n  \"a\" : \"$res.a\",\n  \"b\" : \"$res.b\",\n  \"op\" : \"$res.op\",\n  \"c\" : \"$res.c\"\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_match",
          "httpMethod": "POST",
          "requestTemplates": {
            "application/json": "{\n    \"a\":  \"$input.params('operand1')\",\n    \"b\":  \"$input.params('operand2')\", \n    \"op\": \"$input.params('operator')\"   \n}"
          },
          "type": "aws"
        }
      },
      "post": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "InvocationType",
            "in": "header",
            "required": false,
            "type": "string"
          },
          {
            "in": "body",
            "name": "Input",
            "required": true,
            "schema": {
              "$ref": "#/definitions/Input"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            }
          }
        },
        "x-amazon-apigateway-request-validator": "Validate body",
        "x-amazon-apigateway-integration": {
          "credentials": "arn:aws:iam::123456789012:role/apigAwsProxyRole",
          "responses": {
            "default": {
              "statusCode": "200",
              "responseTemplates": {
                "application/json": "#set($inputRoot = $input.path('$'))\n{\n  \"a\" : $inputRoot.a,\n  \"b\" : $inputRoot.b,\n  \"op\" : $inputRoot.op,\n  \"c\" : $inputRoot.c\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_templates",
          "httpMethod": "POST",
          "type": "aws"
        }
      }
    },
    "/calc/{operand1}/{operand2}/{operator}": {
      "get": {
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "operand2",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "operator",
            "in": "path",
            "required": true,
            "type": "string"
          },
          {
            "name": "operand1",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Result"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "responses": {
            "default": {
              "statusCode": "200",
              "responseTemplates": {
                "application/json": "#set($inputRoot = $input.path('$'))\n{\n  \"input\" : {\n    \"a\" : $inputRoot.a,\n    \"b\" : $inputRoot.b,\n    \"op\" : \"$inputRoot.op\"\n  },\n  \"output\" : {\n    \"c\" : $inputRoot.c\n  }\n}"
              }
            }
          },
          "uri": "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:Calc/invocations",
          "passthroughBehavior": "when_no_templates",
          "httpMethod": "POST",
          "requestTemplates": {
            "application/json": "{\n   \"a\": \"$input.params('operand1')\",\n   \"b\": \"$input.params('operand2')\",\n   \"op\": #if($input.params('operator')=='%2F')\"/\"#{else}\"$input.params('operator')\"#end\n   \n}"
          },
          "contentHandling": "CONVERT_TO_TEXT",
          "type": "aws"
        }
      }
    }
  },
  "definitions": {
    "Input": {
      "type": "object",
      "required": [
        "a",
        "b",
        "op"
      ],
      "properties": {
        "a": {
          "type": "number"
        },
        "b": {
          "type": "number"
        },
        "op": {
          "type": "string",
          "description": "binary op of ['+', 'add', '-', 'sub', '*', 'mul', '%2F', 'div']"
        }
      },
      "title": "Input"
    },
    "Output": {
      "type": "object",
      "properties": {
        "c": {
          "type": "number"
        }
      },
      "title": "Output"
    },
    "Result": {
      "type": "object",
      "properties": {
        "input": {
          "$ref": "#/definitions/Input"
        },
        "output": {
          "$ref": "#/definitions/Output"
        }
      },
      "title": "Result"
    }
  },
  "x-amazon-apigateway-request-validators": {
    "Validate body": {
      "validateRequestParameters": false,
      "validateRequestBody": true
    },
    "Validate query string parameters and headers": {
      "validateRequestParameters": true,
      "validateRequestBody": false
    }
  }
}

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-12-18 (月) 22:15:26 (356d)