'AWS Sam Template use swagger file and template functions for routes

Using AWS::Serverless::API, I am desiring to have route/model validation. Initially I had everything working in the SAM Template. The problem I was having is the AWS::Serverless::Api needed to attach models to it and with my AWS::Serverless::Function routes, I could only use one model per route.

So I decided to switch to using an open api file and going with the oneOf Schema property, but I would like to use it for only the routes that need model validation. It seems as though when I build my template, it ignores all the routes I had previously created and only pulls from my open api file instead of keeping everything I had in place and just overriding the one route.

So I have a few questions.

  1. Can you use an open api file for only 1 route and then use the routes previously in the template file in addition to it.

  2. Can you add multiple models to the AWS::Serverless::Function so that someone could use an object or an array of objects (with validation)

  3. How can you make the open api file actually validate against the model schema because it currently isn't working.

everything has been trimmed down to make it easier to read

template.yaml

AWSTemplateFormatVersion: "2010-09-09"
Description: >-
  demo-api

Transform:
  - AWS::Serverless-2016-10-31

Resources:
  api:
    Type: AWS::Serverless::Api
    DependsOn:
      - authorizer
      - userPool
    Properties:
      StageName: !Ref stage
      Domain:
        DomainName: !If
          - custom
          - !Sub "${customStack}.${developmentDomain}"
          - !FindInMap [domains, !Ref stage, domain]
        CertificateArn: !FindInMap [certificates, !Ref stage, arn]
        Route53:
          HostedZoneId: !FindInMap [zones, !Ref stage, id]
      Cors:
        AllowMethods: "'*'"
        AllowOrigin: "'*'"
        AllowHeaders: "'*'"
      Auth:
        AddDefaultAuthorizerToCorsPreflight: false
        DefaultAuthorizer: lambda
        Authorizers:
          cognito:
            UserPoolArn: !GetAtt userPool.Arn
          lambda:
            FunctionArn: !GetAtt authorizer.Arn
            FunctionPayloadType: REQUEST
            Identity:
              ReauthorizeEvery: 0
      GatewayResponses:
        DEFAULT_4XX:
          ResponseParameters:
            Headers:
              Access-Control-Allow-Origin: "'*'"
        BAD_REQUEST_BODY:
          ResponseTemplates:
            "application/json": '{ "errors": "$context.error.validationErrorString", "message" : "$context.error.messageString" }'
      DefinitionBody:
        Fn::Transform:
          Name: AWS::Include
          Parameters:
            Location: apidefinition.yaml

  getContact:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handlers/contacts/index.get
      Environment:
        Variables:
          CONTACTS_TABLE: !If [custom, !Ref customContacts, !Ref contacts]
      Description: Fetch Contact by id
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !If [custom, !Ref customContacts, !Ref contacts]
      Events:
        Api:
          Type: Api
          Properties:
            RestApiId: !Ref api
            Path: /contacts/{id}
            Method: GET

  getContacts:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handlers/contacts/index.getMany
      Environment:
        Variables:
          CONTACTS_TABLE: !If [custom, !Ref customContacts, !Ref contacts]
      Description: Fetch Contacts
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !If [custom, !Ref customContacts, !Ref contacts]
      Events:
        Api:
          Type: Api
          Properties:
            RestApiId: !Ref api
            Path: /contacts
            Method: GET
            RequestParameters:
              - method.request.querystring.client_id:
                  Required: true
                  Caching: true

  postContact:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handlers/contacts/index.post
      Description: Create Contact
      Environment:
        Variables:
          CONTACTS_TABLE: !If [custom, !Ref customContacts, !Ref contacts]
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !If [custom, !Ref customContacts, !Ref contacts]
      Events:
        Api:
          Type: Api
          Properties:
            RestApiId: !Ref api
            Path: /contacts
            Method: POST


  putContact:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handlers/contacts/index.put
      Environment:
        Variables:
          CONTACTS_TABLE: !If [custom, !Ref customContacts, !Ref contacts]
      Description: Update Contact
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !If [custom, !Ref customContacts, !Ref contacts]
      Events:
        Api:
          Type: Api
          Properties:
            RestApiId: !Ref api
            Path: /contacts/{id}
            Method: PUT

  deleteContact:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handlers/contacts/index.delete
      Environment:
        Variables:
          CONTACTS_TABLE: !If [custom, !Ref customContacts, !Ref contacts]
      Description: Destroy Contact
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !If [custom, !Ref customContacts, !Ref contacts]
      Events:
        Api:
          Type: Api
          Properties:
            RestApiId: !Ref api
            Path: /contacts/{id}
            Method: DELETE

apidefinition.yaml

openapi: 3.0.1
info:
  title: 
    Fn::Sub: "${AWS::StackName}"
  description: testing support of oneOf schema definitions
  version: 0.0.1
x-amazon-apigateway-request-validators:
  #   validateRequestParameters: true
  body:
    validateRequestBody: true
    validateRequestParameters: false

paths:
  /contacts:
    post:
      summary: Create one or many contacts.
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/Contact'
                - $ref: '#/components/schemas/Contacts'
      x-amazon-apigateway-integration:
        type: "aws_proxy"
        uri:
          Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${postContact.Arn}/invocations"
        httpMethod: "POST"
      # x-amazon-apigateway-request-validators:
      #   body:
      #     validateRequestBody: true
      #     validateRequestParameters: false

components:
  schemas:
    Contact:
      title: Contact Object
      type: object
      properties:
        client_id:
          type: number
          title: Associated client ID
        email:
          type: string
          title: Email
        first_name:
          type: string
          title: First Name
        create_time:
          type: integer
          title: Creation time (unix)
      required:
        - email
        - client_id

    Contacts:
      title: Contacts Array
      type: array
      items:
        type: object
        required:
          - email
          - client_id
        properties:
          client_id:
            type: number
            title: Associated client ID
          email:
            type: string
            title: Email
          first_name:
            type: string
            title: First Name
            title: State
          create_time:
            type: integer
            title: Creation time (unix)


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source