ar90n / serverless-s3-local

Serverless s3 local plugin.
MIT License
215 stars 70 forks source link

ApiGateway S3 Proxy #70

Open ed-sparkes opened 5 years ago

ed-sparkes commented 5 years ago

Hi,

I have created an api gateway as proxy to s3 to allow my client to upload items and download items directly as specified here.

This is all specified in cloud formation resources as the serverless framework or plugins dont currently support this. Unfortunately at present it means this part of my architecture cannot be run and tested locally.

Is it feasible to add functionality to serverless-s3-local that would be able to route the resource based routes to local s3 somehow?

Below is my resource spec

Resources:
  s3ItemResource: 
    DependsOn: 
      - ApiGatewayRestApi
      - ApiGatewayResourceS3Proxy
    Type: AWS::ApiGateway::Resource
    Properties: 
      ParentId:
        Ref: ApiGatewayResourceS3Proxy
      PathPart: "{key}"
      RestApiId:
        Ref: ApiGatewayRestApi
  s3ProxyOptionsMethod:
    Type: "AWS::ApiGateway::Method"
    Properties:
      ResourceId: 
        Ref: s3ItemResource 
      RestApiId:
        Ref: ApiGatewayRestApi # Reference API from serverless.yml using Serverless naming convention https://serverless.com/framework/docs/providers/aws/guide/resources/
      AuthorizationType: NONE
      HttpMethod: OPTIONS
      Integration:
        Type: MOCK
        IntegrationResponses:
          - ResponseParameters:
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
              method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS'"
              method.response.header.Access-Control-Allow-Origin: "'*'" # TODO : Can we restrict this further
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: NEVER
        RequestTemplates:
          application/json: '{"statusCode": 200}'
      MethodResponses:
        - ResponseModels:
            application/json: Empty
          ResponseParameters:
            method.response.header.Access-Control-Allow-Headers: true
            method.response.header.Access-Control-Allow-Methods: true
            method.response.header.Access-Control-Allow-Origin: true
          StatusCode: '200'
  s3ProxyGetMethod:
    Type: "AWS::ApiGateway::Method"
    DependsOn: CustomAuthorizerApiGatewayAuthorizer # Reference function Custom Authorizer from serverless.yml using Serverless naming convention https://serverless.com/framework/docs/providers/aws/guide/resources/
    Properties:
      ApiKeyRequired: false
      AuthorizationType: CUSTOM
      AuthorizerId: 
        Ref: CustomAuthorizerApiGatewayAuthorizer # Reference function Custom Authorizer from serverless.yml using Serverless naming convention https://serverless.com/framework/docs/providers/aws/guide/resources/
      HttpMethod: GET
      Integration:
        Credentials: !GetAtt ArtefactRole.Arn
        IntegrationHttpMethod: GET
        IntegrationResponses:
            - StatusCode: 200
              ResponseParameters:
                method.response.header.Content-Type: integration.response.header.Content-Type
                method.response.header.Content-Disposition: integration.response.header.Content-Disposition
                method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
                method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS'"
                method.response.header.Access-Control-Allow-Origin: "'*'" # TODO : Can we restrict this further
            - StatusCode: 400
              SelectionPattern: "400"
              ResponseParameters:
                method.response.header.Content-Type: integration.response.header.Content-Type
                method.response.header.Content-Disposition: integration.response.header.Content-Disposition
            - StatusCode: 404
              SelectionPattern: "404"
              ResponseParameters:
                method.response.header.Content-Type: integration.response.header.Content-Type
                method.response.header.Content-Disposition: integration.response.header.Content-Disposition
            - StatusCode: 500
              SelectionPattern: '5\d{2}'
              ResponseParameters:
                method.response.header.Content-Type: integration.response.header.Content-Type
                method.response.header.Content-Disposition: integration.response.header.Content-Disposition
        PassthroughBehavior: WHEN_NO_MATCH
        RequestParameters:
          integration.request.header.Accept: method.request.header.Accept
          integration.request.path.key: method.request.path.key
        Type: AWS
        Uri: arn:aws:apigateway:${self:provider.region}:s3:path/${self:custom.bucketName}/{key}
      MethodResponses:
        - StatusCode: 200
          ResponseParameters:
            method.response.header.Content-Type: integration.response.header.Content-Type
            method.response.header.Content-Disposition: integration.response.header.Content-Disposition
            method.response.header.Access-Control-Allow-Headers: true
            method.response.header.Access-Control-Allow-Methods: true
            method.response.header.Access-Control-Allow-Origin: true
        - StatusCode: 400
          ResponseParameters:
            method.response.header.Content-Type: integration.response.header.Content-Type
            method.response.header.Content-Disposition: integration.response.header.Content-Disposition
        - StatusCode: 404
          ResponseParameters:
            method.response.header.Content-Type: integration.response.header.Content-Type
            method.response.header.Content-Disposition: integration.response.header.Content-Disposition
        - StatusCode: 500
          ResponseParameters:
            method.response.header.Content-Type: integration.response.header.Content-Type
            method.response.header.Content-Disposition: integration.response.header.Content-Disposition
      RequestParameters:
        method.request.header.Accept: false
        method.request.path.key: false
      ResourceId: 
        Ref: s3ItemResource 
      RestApiId:
        Ref: ApiGatewayRestApi # Reference API from serverless.yml using Serverless naming convention https://serverless.com/framework/docs/providers/aws/guide/resources/
  s3Deployment: # Need to redeploy after creating the resource otherwise the thing foesnt exist (may need to change the name of this deployment on each run using build epoch)
    Type: AWS::ApiGateway::Deployment
    DependsOn: 
      - ApiGatewayDeployment${sls:instanceId}
      - s3ProxyGetMethod
    Properties: 
      Description: Deploy with S3 Getter
      RestApiId:
        Ref: ApiGatewayRestApi
      StageName: ${self:custom.stage}
ar90n commented 5 years ago

@ed-sparkes Thanks for your comment. I think this is a feature of ApiGateway.