AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Hops Serverless Express Application / Powered by hops-lambda

Parameters:
  Runtime:
    Type: String
    Description: Set the Node version of the Lambda runtime; currently only nodejs12.x is supported
    Default: nodejs12.x
    AllowedValues:
      - nodejs12.x
  LambdaMemorySize:
    Type: Number
    MinValue: 128
    MaxValue: 1536
    Description: Specify the amount of memory available to your Lambda function
  StageName:
    Type: String
    Description: The name of the API Gateway stage
  BasePath:
    Type: String
    Description: The base path to append to your domain, when using a custom domain
  BucketName:
    Type: String
    Description: Name of the S3 bucket where your CloudFormation template and zip bundle are stored
  BundleName:
    Type: String
    Description: Name of the zip bundle with your Lambda code
  DomainName:
    Type: String
    Description: A custom domain name
  CertificateArn:
    Type: String
    Description: The Amazon resource name (ARN) of your SSL certificate in ACM

Conditions:
  ShouldAddCustomDomain: !Not [!Equals [!Ref DomainName, '']]
  HasCustomBasePath: !Not [!Equals [!Ref BasePath, '(none)']]

Resources:
  ApiGatewayApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Ref StageName
      DefinitionBody:
        swagger: 2.0
        info:
          title: !Sub 'Hops Serverless Express (${AWS::StackName})'
        basePath: !Sub '/${BasePath}'
        schemes:
          - https
        paths:
          '/':
            x-amazon-apigateway-any-method:
              produces:
                - text/html
              responses: {}
              x-amazon-apigateway-integration:
                uri: !Sub 'arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HopsLambdaHandler.Arn}/invocations'
                passthroughBehavior: when_no_match
                httpMethod: POST
                type: aws_proxy
          '/{proxy+}':
            x-amazon-apigateway-any-method:
              parameters:
                - name: proxy
                  in: path
                  required: true
                  type: string
              produces:
                - text/html
              responses: {}
              x-amazon-apigateway-integration:
                uri: !Sub 'arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HopsLambdaHandler.Arn}/invocations'
                httpMethod: POST
                type: aws_proxy
        x-amazon-apigateway-binary-media-types:
          - '*/*'

  CustomDomainName:
    Type: AWS::ApiGateway::DomainName
    Condition: ShouldAddCustomDomain
    Properties:
      DomainName: !Ref DomainName
      CertificateArn: !Ref CertificateArn

  BasePathMapping:
    Type: AWS::ApiGateway::BasePathMapping
    Condition: ShouldAddCustomDomain
    # https://github.com/awslabs/serverless-application-model/issues/119
    # https://github.com/awslabs/serverless-application-model/issues/70
    DependsOn: ApiGatewayApiStage
    Properties:
      BasePath: !Ref BasePath
      DomainName: !Ref DomainName
      RestApiId: !Ref ApiGatewayApi
      Stage: !Ref StageName

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          Effect: Allow
          Principal:
            Service: !Sub 'lambda.${AWS::URLSuffix}'
          Action: sts:AssumeRole
      Path: '/'
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: !Sub 'arn:${AWS::Partition}:logs:*:*:*'

  LambdaApiGatewayExecutionPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt HopsLambdaHandler.Arn
      Principal: !Sub 'apigateway.${AWS::URLSuffix}'
      SourceArn: !Sub 'arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGatewayApi}/*/*'

  HopsLambdaHandler:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri:
        Bucket: !Ref BucketName
        Key: !Ref BundleName
      Handler: node_modules/hops-lambda/lambda.handler
      MemorySize: !Ref LambdaMemorySize
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: !Ref Runtime
      Timeout: 30
      Events:
        KeepWarm:
          Type: Schedule
          Properties:
            Schedule: rate(5 minutes)
            Input: !Sub >
              {
                "resource": "/",
                "httpMethod": "GET",
                "headers": {
                  "Accept": "x-keep/warm,*/*",
                  "Host": "${ApiGatewayApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}"
                },
                "requestContext": {
                  "path": "/${BasePath}/"
                },
                "body": ""
              }


Outputs:
  DistributionDomainName:
    Value: !If
      - ShouldAddCustomDomain
      - !GetAtt CustomDomainName.DistributionDomainName
      - ''
  Url:
    Value: !If
      - ShouldAddCustomDomain
      - !If [
          HasCustomBasePath,
          !Sub 'https://${DomainName}/${BasePath}/',
          !Sub 'https://${DomainName}/',
        ]
      - !Sub 'https://${ApiGatewayApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/${BasePath}/'
