Terraform API网关与Swagger(Localstack)的集成

时间:2020-01-13 10:54:44

标签: aws-lambda swagger terraform aws-api-gateway localstack

我使用mongoDb和nodeJs创建了一个简单的Crud API lambda,并且运行良好。所以我又走了一步 我当前正在通过使用Yaml文件中的开放api规范创建具有Terraform的AWS API Gateway。 这是我的招摇文件:

info:
  description: "API Ankan-v2"
  version: "V0.0.1"
  title: "ANKAN V2 API"
host: "localhost:4567"
basePath: "/restapis/api/{apiId}/test/_user_request_"
tags:
  - name: "user"
    description: "Operations about user"
schemes:
  - "http"
#    - "https"
paths:
  /documents/{documentId}:
    get:
      tags:
        - "document"
      summary: "Find document by ID"
      description: "Returns a single document"
      operationId: "readOneDocument"
      produces:
        - "application/json"
      parameters:
        - name: "documentId"
          in: "path"
          description: "Id of document"
          required: true
          type: "string"
      responses:
        200:
          description: "successful operation"
          schema:
            $ref: "#/definitions/Document"
        404:
          description: "document not found"
      x-amazon-apigateway-integration:
        uri: ${get_lambda_arn}
        passthroughBehavior: "WHEN_NO_MATCH"
        httpMethod: "POST"
        type: "AWS_PROXY"
    options:
      consumes:
        - "application/json"
      produces:
        - "application/json"
      parameters:
        - name: "documentId"
          in: "path"
          description: "Id of document"
          required: true
          type: "string"
      responses:
        200:
          description: "200 response"
          schema:
            $ref: "#/definitions/Document"
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
            responseParameters:
              method.response.header.Access-Control-Allow-Methods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
              method.response.header.Access-Control-Allow-Origin: "'*'"
        requestTemplates:
          application/json: "{\"statusCode\": 200}"
        passthroughBehavior: "when_no_match"
        type: "mock"
    x-amazon-apigateway-any-method:
      produces:
        - "application/json"
      parameters:
        - name: "documentId"
          in: "path"
          description: "Id of document"
          required: true
          type: "string"
      responses: {}
      x-amazon-apigateway-integration:
        responses:
          default:
            statusCode: "200"
        uri: ${get_lambda_arn}
        passthroughBehavior: "WHEN_NO_MATCH"
        httpMethod: "POST"
        cacheNamespace: "1rnijn"
        cacheKeyParameters:
          - "method.request.path.documentId"
        type: "AWS"
definitions:
  Document:
    type: "object"
    required:
      - "documentName"
      - "documentPath"
      - "miniature"
      - "status"
      - "date"
    properties:
      _id:
        type: "string"
        readOnly: true
      documentName:
        type: "string"
      documentPath:
        type: "string"
      miniature:
        type: "string"
      status:
        type: "string"
        enum:
          - "VALID"
          - "ERROR"
          - "ONLOAD"
      date:
        type: "string"
        format: "date"
    xml:
      name: "Document" 

在我的地形中,我删除了集成和方法,因为我将它们添加到了我的招摇中。 所以我需要使用body = data.template_file.swagger.rendered

将av_api文件导入aws_api_gateway_rest_api
resource "aws_api_gateway_rest_api" "api" {
  name = "api-gateway"
  description = "document api"
  body = data.template_file.swagger.rendered

}


data "template_file" "swagger" {
  template = jsonencode("${path.module}/../../../../shared/swagger.yaml")

  vars = {
    get_lambda_arn = local.get_lambda_arn
  }
}
output "json" {
  value = data.template_file.swagger.rendered
}

locals {
  get_lambda_arn = aws_lambda_function.lambda_document.invoke_arn
}

resource "aws_api_gateway_resource" "documents" {
  rest_api_id = aws_api_gateway_rest_api.api.id
  parent_id   = aws_api_gateway_rest_api.api.root_resource_id
  path_part   = "documents"
  depends_on  = [aws_api_gateway_rest_api.api]
}

resource "aws_api_gateway_resource" "document_by_id" {
  parent_id   = aws_api_gateway_resource.documents.id
  path_part   = "{documentId}"
  rest_api_id = aws_api_gateway_rest_api.api.id
}


resource "aws_api_gateway_deployment" "ApiDeloyment" {
  rest_api_id = aws_api_gateway_rest_api.api.id
  stage_name = "INT"

  depends_on = [aws_api_gateway_rest_api.api]
}


resource "aws_lambda_function" "lambda_document" {
  function_name = "lambda_document"
  handler = "lambda.handler"
  role = "arn:aws::iam::123456:role/irrelevant"
  runtime = "nodejs10.x"
  filename = "${path.module}/lambda.zip"

  source_code_hash = filebase64sha256("${path.module}/lambda.zip")
}

在应用Terraform后,我在Terraform日志中收到了此消息

terraform apply --auto-approve
module.backend_api.module.document.aws_api_gateway_rest_api.api: Creating...
module.backend_api.module.document.aws_lambda_function.lambda_document: Creating...
module.backend_api.module.document.aws_lambda_function.lambda_document: Creation complete after 5s [id=lambda_document]
module.backend_api.module.document.data.template_file.swagger: Refreshing state...
module.backend_api.module.document.aws_api_gateway_rest_api.api: Still creating... [10s elapsed]
module.backend_api.module.document.aws_api_gateway_rest_api.api: Still creating... [20s elapsed]
module.backend_api.module.document.aws_api_gateway_rest_api.api: Still creating... [30s elapsed]
module.backend_api.module.document.aws_api_gateway_rest_api.api: Still creating... [40s elapsed]
module.backend_api.module.document.aws_api_gateway_rest_api.api: Still creating... [50s elapsed]
module.backend_api.module.document.aws_api_gateway_rest_api.api: Still creating... [1m0s elapsed]
module.backend_api.module.document.aws_api_gateway_rest_api.api: Still creating... [1m10s elapsed]

和我的docker-compose日志显示了

localstack        | 2020-01-13T07:37:56:ERROR:localstack.services.generic_proxy: Error forwarding request: Expecting value: line 1 column 1 (char 0) Traceback (most recent call last):
localstack        |   File "/opt/code/localstack/localstack/services/generic_proxy.py", line 242, in forward
localstack        |     path=path, data=data, headers=forward_headers)
localstack        |   File "/opt/code/localstack/localstack/services/apigateway/apigateway_listener.py", line 53, in forward_request
localstack        |     data = data and json.loads(to_str(data))
localstack        |   File "/usr/lib/python3.7/json/__init__.py", line 348, in loads
localstack        |     return _default_decoder.decode(s)
localstack        |   File "/usr/lib/python3.7/json/decoder.py", line 337, in decode
localstack        |     obj, end = self.raw_decode(s, idx=_w(s, 0).end())
localstack        |   File "/usr/lib/python3.7/json/decoder.py", line 355, in raw_decode
localstack        |     raise JSONDecodeError("Expecting value", s, err.value) from None
localstack        | json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

PS:我尝试使用JSON但存在相同问题

有什么解决办法吗?我想在本地堆栈中使用Terraform将swagger与api网关集成

1 个答案:

答案 0 :(得分:1)

这是moto库的问题。在后台,本地堆栈使用moto创建其资源,包括模拟api网关。不幸的是,moto当前不支持将body参数定义作为api网关部署的一部分放置的body参数。因此,即使您提供了有效的swagger文件和api网关配置(即可在aws中运行的配置),localstack也将无法构建它。