template/master-fullstack-with-lambda-warmers.yaml [1725:2970]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        SubnetIds:
          - Ref: bookstoreSubnet1
      Code:
        S3Bucket: !FindInMap 
          - S3Buckets
          - !Ref 'AWS::Region'
          - Bucket
        S3Key: !FindInMap 
          - Constants
          - S3Keys
          - SearchCode
      Environment:
        Variables:
          ESENDPOINT: !GetAtt 
            - ElasticsearchDomain
            - DomainEndpoint
          REGION: !Ref 'AWS::Region'
  FunctionGetBestSellers:
    Type: 'AWS::Lambda::Function'
    DependsOn:
      - RedisRole
      - ElastiCacheCluster
      - TOrders
    Properties:
      FunctionName: !Sub '${ProjectName}-GetBestSellers'
      Description: Get the top 20 best selling books from ElastiCache
      Handler: index.handler
      MemorySize: 256
      Role: !GetAtt
        - RedisRole
        - Arn
      Runtime: nodejs8.10
      Timeout: '60'
      VpcConfig:
        SecurityGroupIds:
          - Ref: redisLambdaSecurityGroup
        SubnetIds:
          - Ref: bookstoreSubnet1
      Code:
        S3Bucket: !FindInMap 
          - S3Buckets
          - !Ref 'AWS::Region'
          - Bucket
        S3Key: !FindInMap 
          - Constants
          - S3Keys
          - GetBestSellersCode
      Environment:
        Variables:
          URL: !GetAtt 
            - ElastiCacheCluster
            - RedisEndpoint.Address          
  
 # ---------- LAMBDA PERMISSIONS ---------    
  FunctionListOrdersPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionListOrders
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionGetRecommendationsPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionGetRecommendations
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
  FunctionGetRecommendationsByBookPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionGetRecommendationsByBook
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /* 
  FunctionGetBookPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionGetBook
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionListBooksPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionListBooks
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionUpdateCartPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionUpdateCart
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionGetCartItemPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionGetCartItem
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionListItemsInCartPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionListItemsInCart
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionAddToCartPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionAddToCart
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionRemoveFromCartPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionRemoveFromCart
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionCheckoutPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionCheckout
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionSearchPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionSearch
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionGetBestSellersPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionGetBestSellers
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c  

 # ---------- API GATEWAY ---------         
  AppApi:
    Type: 'AWS::ApiGateway::RestApi'
    Properties:
      Name: !Sub '${ProjectName}-Bookstore'
      Description: API used for Bookstore requests
      FailOnWarnings: true
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 3e7a32d4-9e4d-4ecc-89b2-77203c5d926b
  RecomendationsApiRequestGET:
    DependsOn:
      - FunctionGetRecommendations
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionGetRecommendations
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref RecommendationsApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
  RecomendationsApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref RecommendationsApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
  RecomendationsByBookApiRequestGET:
    DependsOn:
      - FunctionGetRecommendationsByBook
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionGetRecommendationsByBook
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref RecommendationsByBookApiResource
      RequestParameters:
        method.request.path.bookId: false
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
  RecomendationsByBookApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref RecommendationsByBookApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'        
  BooksApiRequestGET:
    DependsOn:
      - FunctionListOrdersPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionListBooks
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      RequestParameters:
        method.request.querystring.category: false
      ResourceId: !Ref BooksApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 5a740957-6b64-4ddd-bd1d-3027df7fc6d5
  BooksApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref BooksApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: f0f16a94-104a-431f-8c87-930f56274955
  BookItemApiRequestGET:
    DependsOn: FunctionGetBookPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionGetBook
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
            ResponseTemplates:
              application/json: $input.json('$.body')
      RequestParameters:
        method.request.path.id: true
      ResourceId: !Ref BookItemApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a311ee38-d902-4856-9f09-1d00d1bc8600
  BookItemApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref BookItemApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: c31e25ac-e338-4d21-9e4b-881a16e0a494
  OrdersApiRequestGET:
    DependsOn: FunctionListOrdersPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionListOrders
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref OrdersApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 9007f88f-407a-4ab7-9ebb-ce6fa13b223e
  OrdersApiRequestPOST:
    DependsOn: FunctionCheckoutPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: POST
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionCheckout
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref OrdersApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 454289ef-fb5c-4a1f-941d-4016ebc9cf24
  OrdersApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref OrdersApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: e97bf15c-b88b-48b7-b6d8-bffcaa87b24f
  CartApiRequestGET:
    DependsOn: FunctionListItemsInCartPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionListItemsInCart
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref CartApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 3023c794-550d-4066-8a59-c139f4f54616
  CartApiRequestPOST:
    DependsOn: FunctionAddToCartPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: POST
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionAddToCart
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref CartApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 49458e1d-a6a5-4c44-96b5-f1e3f6c694a8
  CartApiRequestPUT:
    DependsOn: FunctionUpdateCartPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: PUT
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionUpdateCart
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref CartApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 6a4462a7-45d0-4bd9-a08a-03cd5621e0ce
  CartApiRequestDELETE:
    DependsOn: FunctionRemoveFromCartPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: DELETE
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionRemoveFromCart
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      RequestParameters:
        method.request.path.id: true
      ResourceId: !Ref CartApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a6392891-b014-4ea9-93a2-831f602268aa
  CartApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref CartApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 97efc723-a637-41c7-b712-3af9363a1702
  CartItemApiRequestGET:
    DependsOn: FunctionGetCartItemPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionGetCartItem
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      RequestParameters:
        method.request.path.bookId: true
      ResourceId: !Ref CartItemApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: acebdfda-9b64-45f8-a888-3d1251bba41a
  CartItemApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref CartItemApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 0e6ce8f6-0271-439e-afcf-4e4d23c1edc3
  SearchApiRequestGET:
    DependsOn: FunctionSearchPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionSearch
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      RequestParameters:
        method.request.querystring.q: false
      ResourceId: !Ref SearchApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
  SearchApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref SearchApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
  BestsellersApiRequestGET:
    DependsOn: FunctionGetBestSellersPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionGetBestSellers
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref BestsellersApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
  BestsellersApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref BestsellersApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
          
  RecommendationsApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: recommendations
  RecommendationsByBookApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !Ref RecommendationsApiResource
      PathPart: '{bookId}'    
  BooksApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: books
    Metadata:
      'AWS::CloudFormation::Designer':
        id: e0ffbcc7-5f62-43ac-b377-47ec80a5a71e
  BookItemApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !Ref BooksApiResource
      PathPart: '{id}'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 25b4ecc5-9d47-49cb-b5c4-d03574eee62e
  OrdersApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: orders
    Metadata:
      'AWS::CloudFormation::Designer':
        id: cecab4d7-120d-48b2-99d9-1152b429cebc
  CartApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: cart
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 9747c416-4f2e-45b1-bc9d-16335256f1db
  CartItemApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !Ref CartApiResource
      PathPart: '{bookId}'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a79e1eec-10b0-4593-9ea4-9c6b82c0ec8b
  SearchApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: search
  BestsellersApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: bestsellers 

  ApiAuthorizer:
    Type: 'AWS::ApiGateway::Authorizer'
    Properties:
      AuthorizerResultTtlInSeconds: 300
      IdentitySource: method.request.header.Authorization
      Name: CognitoDefaultUserPoolAuthorizer
      ProviderARNs:
        - !GetAtt 
          - UserPool
          - Arn
      RestApiId: !Ref AppApi
      Type: COGNITO_USER_POOLS
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 03db03b0-3367-4eb8-bfa1-82df7efc4df4
  APIDeployment:
    DependsOn:
      - BooksApiRequestGET
      - BooksApiRequestOPTIONS
      - BookItemApiRequestGET
      - BookItemApiRequestOPTIONS
      - OrdersApiRequestGET
      - OrdersApiRequestPOST
      - OrdersApiRequestOPTIONS
      - CartApiRequestGET
      - CartApiRequestPUT
      - CartApiRequestPOST
      - CartApiRequestDELETE
      - CartApiRequestOPTIONS
      - CartItemApiRequestGET
      - CartItemApiRequestOPTIONS
      - RecomendationsApiRequestGET
      - RecomendationsApiRequestOPTIONS
      - RecomendationsByBookApiRequestGET
      - RecomendationsByBookApiRequestOPTIONS
      - SearchApiRequestGET
      - SearchApiRequestOPTIONS
      - BestsellersApiRequestGET
      - BestsellersApiRequestOPTIONS
    Type: 'AWS::ApiGateway::Deployment'
    Properties:
      Description: Prod deployment for API
      RestApiId: !Ref AppApi
      StageName: prod
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 278dda65-02c9-49fa-a19c-3dd7afd25683

# ---------- COGNITO DEFINITIONS ---------           
  SNSRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - cognito-idp.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Policies:
        - PolicyName: CognitoSNSPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: 'sns:publish'
                Resource: '*'
  UserPool:
    Type: 'AWS::Cognito::UserPool'
    Properties:
      UserPoolName: !Sub '${ProjectName}-user-pool'
      UsernameAttributes:
        - email
      AdminCreateUserConfig:
        AllowAdminCreateUserOnly: false
        InviteMessageTemplate:
          EmailMessage: 'Your username is {username} and temporary password is {####}. '
          EmailSubject: Your temporary password
          SMSMessage: 'Your username is {username} and temporary password is {####}.'
        UnusedAccountValidityDays: 7
      Policies:
        PasswordPolicy:
          MinimumLength: 8
          RequireLowercase: false
          RequireNumbers: false
          RequireSymbols: false
          RequireUppercase: false
      AutoVerifiedAttributes:
        - email
      EmailVerificationMessage: 'Here is your verification code: {####}'
      EmailVerificationSubject: Your verification code
      Schema:
        - Name: email
          AttributeDataType: String
          Mutable: false
          Required: true
  UserPoolClient:
    Type: 'AWS::Cognito::UserPoolClient'
    Properties:
      ClientName: !Sub '${ProjectName}-client'
      GenerateSecret: false
      UserPoolId: !Ref UserPool
  IdentityPool:
    Type: 'AWS::Cognito::IdentityPool'
    Properties:
      IdentityPoolName: !Sub '${ProjectName}Identity'
      AllowUnauthenticatedIdentities: true
      CognitoIdentityProviders:
        - ClientId: !Ref UserPoolClient
          ProviderName: !GetAtt 
            - UserPool
            - ProviderName
  CognitoUnAuthorizedRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Federated: cognito-identity.amazonaws.com
            Action:
              - 'sts:AssumeRoleWithWebIdentity'
            Condition:
              StringEquals:
                'cognito-identity.amazonaws.com:aud': !Ref IdentityPool
              'ForAnyValue:StringLike':
                'cognito-identity.amazonaws.com:amr': unauthenticated
      Policies:
        - PolicyName: CognitoUnauthorizedPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'mobileanalytics:PutEvents'
                  - 'cognito-sync:*'
                Resource: '*'
  CognitoAuthorizedRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Federated: cognito-identity.amazonaws.com
            Action:
              - 'sts:AssumeRoleWithWebIdentity'
            Condition:
              StringEquals:
                'cognito-identity.amazonaws.com:aud': !Ref IdentityPool
              'ForAnyValue:StringLike':
                'cognito-identity.amazonaws.com:amr': authenticated
      Policies:
        - PolicyName: CognitoAuthorizedPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'mobileanalytics:PutEvents'
                  - 'cognito-sync:*'
                  - 'cognito-identity:*'
                Resource: '*'
              - Effect: Allow
                Action:
                  - 'execute-api:Invoke'
                Resource: !Join 
                  - ''
                  - - 'arn:aws:execute-api:'
                    - !Ref 'AWS::Region'
                    - ':'
                    - !Ref 'AWS::AccountId'
                    - ':'
                    - !Ref AppApi
                    - /*
  IdentityPoolRoleMapping:
    Type: 'AWS::Cognito::IdentityPoolRoleAttachment'
    Properties:
      IdentityPoolId: !Ref IdentityPool
      Roles:
        authenticated: !GetAtt 
          - CognitoAuthorizedRole
          - Arn
        unauthenticated: !GetAtt 
          - CognitoUnAuthorizedRole
          - Arn
  BooksUploader:
    Type: 'Custom::CustomResource'
    Properties:
      ServiceToken: !GetAtt FunctionUploadBooks.Arn
      ParameterOne: Parameter to pass into Custom Lambda Function
      DependsOn: 
       - FunctionUploadBooks
       - UpdateSearchCluster
       - ElasticsearchDomain

# ------------------------ FRONTEND ------------------------
  AssetsCodeRepository:
    Type: 'AWS::CodeCommit::Repository'
    Properties:
      RepositoryDescription: Code repository for web application
      RepositoryName: !Sub '${ProjectName}-WebAssets'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a2e798f0-374b-4297-b68f-ce7766170a6d
  AssetsBucket:
    Type: 'AWS::S3::Bucket'
    Properties:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



template/master-fullstack.yaml [1258:2503]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        SubnetIds:
          - Ref: bookstoreSubnet1
      Code:
        S3Bucket: !FindInMap 
          - S3Buckets
          - !Ref 'AWS::Region'
          - Bucket
        S3Key: !FindInMap 
          - Constants
          - S3Keys
          - SearchCode
      Environment:
        Variables:
          ESENDPOINT: !GetAtt 
            - ElasticsearchDomain
            - DomainEndpoint
          REGION: !Ref 'AWS::Region'
  FunctionGetBestSellers:
    Type: 'AWS::Lambda::Function'
    DependsOn:
      - RedisRole
      - ElastiCacheCluster
      - TOrders
    Properties:
      FunctionName: !Sub '${ProjectName}-GetBestSellers'
      Description: Get the top 20 best selling books from ElastiCache
      Handler: index.handler
      MemorySize: 256
      Role: !GetAtt
        - RedisRole
        - Arn
      Runtime: nodejs8.10
      Timeout: '60'
      VpcConfig:
        SecurityGroupIds:
          - Ref: redisLambdaSecurityGroup
        SubnetIds:
          - Ref: bookstoreSubnet1
      Code:
        S3Bucket: !FindInMap 
          - S3Buckets
          - !Ref 'AWS::Region'
          - Bucket
        S3Key: !FindInMap 
          - Constants
          - S3Keys
          - GetBestSellersCode
      Environment:
        Variables:
          URL: !GetAtt 
            - ElastiCacheCluster
            - RedisEndpoint.Address          
  
 # ---------- LAMBDA PERMISSIONS ---------    
  FunctionListOrdersPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionListOrders
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionGetRecommendationsPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionGetRecommendations
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
  FunctionGetRecommendationsByBookPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionGetRecommendationsByBook
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /* 
  FunctionGetBookPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionGetBook
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionListBooksPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionListBooks
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionUpdateCartPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionUpdateCart
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionGetCartItemPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionGetCartItem
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionListItemsInCartPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionListItemsInCart
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionAddToCartPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionAddToCart
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionRemoveFromCartPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionRemoveFromCart
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionCheckoutPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionCheckout
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionSearchPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionSearch
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c
  FunctionGetBestSellersPermissions:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !Ref FunctionGetBestSellers
      Principal: apigateway.amazonaws.com
      SourceArn: !Join 
        - ''
        - - 'arn:aws:execute-api:'
          - !Ref 'AWS::Region'
          - ':'
          - !Ref 'AWS::AccountId'
          - ':'
          - !Ref AppApi
          - /*
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 06a821b7-638e-471c-ab50-51710b73767c  

 # ---------- API GATEWAY ---------         
  AppApi:
    Type: 'AWS::ApiGateway::RestApi'
    Properties:
      Name: !Sub '${ProjectName}-Bookstore'
      Description: API used for Bookstore requests
      FailOnWarnings: true
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 3e7a32d4-9e4d-4ecc-89b2-77203c5d926b
  RecomendationsApiRequestGET:
    DependsOn:
      - FunctionGetRecommendations
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionGetRecommendations
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref RecommendationsApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
  RecomendationsApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref RecommendationsApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
  RecomendationsByBookApiRequestGET:
    DependsOn:
      - FunctionGetRecommendationsByBook
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionGetRecommendationsByBook
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref RecommendationsByBookApiResource
      RequestParameters:
        method.request.path.bookId: false
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
  RecomendationsByBookApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref RecommendationsByBookApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'        
  BooksApiRequestGET:
    DependsOn:
      - FunctionListOrdersPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionListBooks
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      RequestParameters:
        method.request.querystring.category: false
      ResourceId: !Ref BooksApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 5a740957-6b64-4ddd-bd1d-3027df7fc6d5
  BooksApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref BooksApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: f0f16a94-104a-431f-8c87-930f56274955
  BookItemApiRequestGET:
    DependsOn: FunctionGetBookPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionGetBook
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
            ResponseTemplates:
              application/json: $input.json('$.body')
      RequestParameters:
        method.request.path.id: true
      ResourceId: !Ref BookItemApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a311ee38-d902-4856-9f09-1d00d1bc8600
  BookItemApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref BookItemApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: c31e25ac-e338-4d21-9e4b-881a16e0a494
  OrdersApiRequestGET:
    DependsOn: FunctionListOrdersPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionListOrders
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref OrdersApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 9007f88f-407a-4ab7-9ebb-ce6fa13b223e
  OrdersApiRequestPOST:
    DependsOn: FunctionCheckoutPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: POST
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionCheckout
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref OrdersApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 454289ef-fb5c-4a1f-941d-4016ebc9cf24
  OrdersApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref OrdersApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: e97bf15c-b88b-48b7-b6d8-bffcaa87b24f
  CartApiRequestGET:
    DependsOn: FunctionListItemsInCartPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionListItemsInCart
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref CartApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 3023c794-550d-4066-8a59-c139f4f54616
  CartApiRequestPOST:
    DependsOn: FunctionAddToCartPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: POST
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionAddToCart
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref CartApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 49458e1d-a6a5-4c44-96b5-f1e3f6c694a8
  CartApiRequestPUT:
    DependsOn: FunctionUpdateCartPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: PUT
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionUpdateCart
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref CartApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 6a4462a7-45d0-4bd9-a08a-03cd5621e0ce
  CartApiRequestDELETE:
    DependsOn: FunctionRemoveFromCartPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: DELETE
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionRemoveFromCart
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      RequestParameters:
        method.request.path.id: true
      ResourceId: !Ref CartApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a6392891-b014-4ea9-93a2-831f602268aa
  CartApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref CartApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 97efc723-a637-41c7-b712-3af9363a1702
  CartItemApiRequestGET:
    DependsOn: FunctionGetCartItemPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionGetCartItem
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      RequestParameters:
        method.request.path.bookId: true
      ResourceId: !Ref CartItemApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
    Metadata:
      'AWS::CloudFormation::Designer':
        id: acebdfda-9b64-45f8-a888-3d1251bba41a
  CartItemApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref CartItemApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 0e6ce8f6-0271-439e-afcf-4e4d23c1edc3
  SearchApiRequestGET:
    DependsOn: FunctionSearchPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionSearch
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      RequestParameters:
        method.request.querystring.q: false
      ResourceId: !Ref SearchApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
  SearchApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref SearchApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
  BestsellersApiRequestGET:
    DependsOn: FunctionGetBestSellersPermissions
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: AWS_IAM
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Join 
          - ''
          - - 'arn:aws:apigateway:'
            - !Ref 'AWS::Region'
            - ':lambda:path/2015-03-31/functions/'
            - !GetAtt 
              - FunctionGetBestSellers
              - Arn
            - /invocations
        IntegrationResponses:
          - StatusCode: 200
      ResourceId: !Ref BestsellersApiResource
      RestApiId: !Ref AppApi
      MethodResponses:
        - StatusCode: 200
          ResponseModels:
            application/json: Empty
  BestsellersApiRequestOPTIONS:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      ResourceId: !Ref BestsellersApiResource
      RestApiId: !Ref AppApi
      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,POST,PUT,DELETE,OPTIONS,HEAD,PATCH'''
              method.response.header.Access-Control-Allow-Origin: '''*'''
            ResponseTemplates:
              application/json: ''
            StatusCode: '200'
        PassthroughBehavior: WHEN_NO_MATCH
        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'
          
  RecommendationsApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: recommendations
  RecommendationsByBookApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !Ref RecommendationsApiResource
      PathPart: '{bookId}'    
  BooksApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: books
    Metadata:
      'AWS::CloudFormation::Designer':
        id: e0ffbcc7-5f62-43ac-b377-47ec80a5a71e
  BookItemApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !Ref BooksApiResource
      PathPart: '{id}'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 25b4ecc5-9d47-49cb-b5c4-d03574eee62e
  OrdersApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: orders
    Metadata:
      'AWS::CloudFormation::Designer':
        id: cecab4d7-120d-48b2-99d9-1152b429cebc
  CartApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: cart
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 9747c416-4f2e-45b1-bc9d-16335256f1db
  CartItemApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !Ref CartApiResource
      PathPart: '{bookId}'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a79e1eec-10b0-4593-9ea4-9c6b82c0ec8b
  SearchApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: search
  BestsellersApiResource:
    Type: 'AWS::ApiGateway::Resource'
    Properties:
      RestApiId: !Ref AppApi
      ParentId: !GetAtt 
        - AppApi
        - RootResourceId
      PathPart: bestsellers 

  ApiAuthorizer:
    Type: 'AWS::ApiGateway::Authorizer'
    Properties:
      AuthorizerResultTtlInSeconds: 300
      IdentitySource: method.request.header.Authorization
      Name: CognitoDefaultUserPoolAuthorizer
      ProviderARNs:
        - !GetAtt 
          - UserPool
          - Arn
      RestApiId: !Ref AppApi
      Type: COGNITO_USER_POOLS
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 03db03b0-3367-4eb8-bfa1-82df7efc4df4
  APIDeployment:
    DependsOn:
      - BooksApiRequestGET
      - BooksApiRequestOPTIONS
      - BookItemApiRequestGET
      - BookItemApiRequestOPTIONS
      - OrdersApiRequestGET
      - OrdersApiRequestPOST
      - OrdersApiRequestOPTIONS
      - CartApiRequestGET
      - CartApiRequestPUT
      - CartApiRequestPOST
      - CartApiRequestDELETE
      - CartApiRequestOPTIONS
      - CartItemApiRequestGET
      - CartItemApiRequestOPTIONS
      - RecomendationsApiRequestGET
      - RecomendationsApiRequestOPTIONS
      - RecomendationsByBookApiRequestGET
      - RecomendationsByBookApiRequestOPTIONS
      - SearchApiRequestGET
      - SearchApiRequestOPTIONS
      - BestsellersApiRequestGET
      - BestsellersApiRequestOPTIONS
    Type: 'AWS::ApiGateway::Deployment'
    Properties:
      Description: Prod deployment for API
      RestApiId: !Ref AppApi
      StageName: prod
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 278dda65-02c9-49fa-a19c-3dd7afd25683

# ---------- COGNITO DEFINITIONS ---------           
  SNSRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - cognito-idp.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Policies:
        - PolicyName: CognitoSNSPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: 'sns:publish'
                Resource: '*'
  UserPool:
    Type: 'AWS::Cognito::UserPool'
    Properties:
      UserPoolName: !Sub '${ProjectName}-user-pool'
      UsernameAttributes:
        - email
      AdminCreateUserConfig:
        AllowAdminCreateUserOnly: false
        InviteMessageTemplate:
          EmailMessage: 'Your username is {username} and temporary password is {####}. '
          EmailSubject: Your temporary password
          SMSMessage: 'Your username is {username} and temporary password is {####}.'
        UnusedAccountValidityDays: 7
      Policies:
        PasswordPolicy:
          MinimumLength: 8
          RequireLowercase: false
          RequireNumbers: false
          RequireSymbols: false
          RequireUppercase: false
      AutoVerifiedAttributes:
        - email
      EmailVerificationMessage: 'Here is your verification code: {####}'
      EmailVerificationSubject: Your verification code
      Schema:
        - Name: email
          AttributeDataType: String
          Mutable: false
          Required: true
  UserPoolClient:
    Type: 'AWS::Cognito::UserPoolClient'
    Properties:
      ClientName: !Sub '${ProjectName}-client'
      GenerateSecret: false
      UserPoolId: !Ref UserPool
  IdentityPool:
    Type: 'AWS::Cognito::IdentityPool'
    Properties:
      IdentityPoolName: !Sub '${ProjectName}Identity'
      AllowUnauthenticatedIdentities: true
      CognitoIdentityProviders:
        - ClientId: !Ref UserPoolClient
          ProviderName: !GetAtt 
            - UserPool
            - ProviderName
  CognitoUnAuthorizedRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Federated: cognito-identity.amazonaws.com
            Action:
              - 'sts:AssumeRoleWithWebIdentity'
            Condition:
              StringEquals:
                'cognito-identity.amazonaws.com:aud': !Ref IdentityPool
              'ForAnyValue:StringLike':
                'cognito-identity.amazonaws.com:amr': unauthenticated
      Policies:
        - PolicyName: CognitoUnauthorizedPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'mobileanalytics:PutEvents'
                  - 'cognito-sync:*'
                Resource: '*'
  CognitoAuthorizedRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Federated: cognito-identity.amazonaws.com
            Action:
              - 'sts:AssumeRoleWithWebIdentity'
            Condition:
              StringEquals:
                'cognito-identity.amazonaws.com:aud': !Ref IdentityPool
              'ForAnyValue:StringLike':
                'cognito-identity.amazonaws.com:amr': authenticated
      Policies:
        - PolicyName: CognitoAuthorizedPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'mobileanalytics:PutEvents'
                  - 'cognito-sync:*'
                  - 'cognito-identity:*'
                Resource: '*'
              - Effect: Allow
                Action:
                  - 'execute-api:Invoke'
                Resource: !Join 
                  - ''
                  - - 'arn:aws:execute-api:'
                    - !Ref 'AWS::Region'
                    - ':'
                    - !Ref 'AWS::AccountId'
                    - ':'
                    - !Ref AppApi
                    - /*
  IdentityPoolRoleMapping:
    Type: 'AWS::Cognito::IdentityPoolRoleAttachment'
    Properties:
      IdentityPoolId: !Ref IdentityPool
      Roles:
        authenticated: !GetAtt 
          - CognitoAuthorizedRole
          - Arn
        unauthenticated: !GetAtt 
          - CognitoUnAuthorizedRole
          - Arn
  BooksUploader:
    Type: 'Custom::CustomResource'
    Properties:
      ServiceToken: !GetAtt FunctionUploadBooks.Arn
      ParameterOne: Parameter to pass into Custom Lambda Function
      DependsOn: 
       - FunctionUploadBooks
       - UpdateSearchCluster
       - ElasticsearchDomain

# ------------------------ FRONTEND ------------------------
  AssetsCodeRepository:
    Type: 'AWS::CodeCommit::Repository'
    Properties:
      RepositoryDescription: Code repository for web application
      RepositoryName: !Sub '${ProjectName}-WebAssets'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a2e798f0-374b-4297-b68f-ce7766170a6d
  AssetsBucket:
    Type: 'AWS::S3::Bucket'
    Properties:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



