AWSTemplateFormatVersion: 2010-09-09 Description: AppSync setup Parameters: FunctionStack: Description: The stack name that deploys the Lambda functions to invoke. Type: String Resources: DataSourceRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: appsync.amazonaws.com Policies: - PolicyName: LambdaInvoker PolicyDocument: Version: 2012-10-17 Statement: - Action: lambda:InvokeFunction Effect: Allow Resource: - Fn::Join: - '' - - 'arn:aws:lambda:' - !Ref AWS::Region - ':' - !Ref AWS::AccountId - ':function:' - Fn::ImportValue: !Sub '${FunctionStack}-functions-Decision' - Fn::Join: - '' - - 'arn:aws:lambda:' - !Ref AWS::Region - ':' - !Ref AWS::AccountId - ':function:' - Fn::ImportValue: !Sub '${FunctionStack}-functions-Decision' - ':*' - Fn::Join: - '' - - 'arn:aws:lambda:' - !Ref AWS::Region - ':' - !Ref AWS::AccountId - ':function:' - Fn::ImportValue: !Sub '${FunctionStack}-functions-Transaction' - Fn::Join: - '' - - 'arn:aws:lambda:' - !Ref AWS::Region - ':' - !Ref AWS::AccountId - ':function:' - Fn::ImportValue: !Sub '${FunctionStack}-functions-Transaction' - ':*' RoleName: !Sub '${AWS::StackName}-lambda-role' GqlApi: Type: AWS::AppSync::GraphQLApi Properties: AuthenticationType: AWS_IAM Name: !Ref AWS::StackName GqlSchema: Type: AWS::AppSync::GraphQLSchema Properties: ApiId: !GetAtt GqlApi.ApiId Definition: | type Mutation { postDecision(decision: DecisionInput! cognitoIdentityId__: String): ! postTransaction(transaction: TransactionInput! cognitoIdentityId__: String): Decision! } type Query { } input AdditionalDataInput { inAuthId: String } type AdditionalData { inAuthId: String! } input AddressInput { city: String country: String name: String state: String streetLineOne: String streetLineTwo: String zip: String } type Address { city: String! country: String! name: String! state: String! streetLineOne: String! streetLineTwo: String zip: String! } input CreditCardInput { authCode: String authorizedAmount: Float avsResponse: String billingAddress: AddressInput cardNumber: String cardType: String expiryDate: String fullAmount: Float merchantId: Int nameOnCard: String registerNumber: String responseCode: Int transactionNumber: String } type CreditCard { authCode: String! authorizedAmount: Float! avsResponse: String! billingAddress: Address! cardNumber: String! cardType: String! expiryDate: String! fullAmount: Float! merchantId: Int nameOnCard: String! registerNumber: String responseCode: Int! transactionNumber: String! } input CustomerInput { accountId: String creationDate: AWSDate customerType: CustomerType emailAddress: String firstName: String lastName: String } type Customer { accountId: String! creationDate: AWSDate! customerType: CustomerType! emailAddress: String! firstName: String! lastName: String! } input DBRecordInput { createdDate: AWSDate decision: DecisionInput lastModifiedDate: AWSDate transaction: TransactionInput transactionId: String } type DBRecord { createdDate: AWSDate decision: Decision! lastModifiedDate: AWSDate transaction: Transaction! transactionId: String! } input DecisionInput { crossReference: String recommendationCode: RecommendationCode remarks: String rulesTripped: String totalScore: Int transactionId: String } type Decision { crossReference: String recommendationCode: RecommendationCode! remarks: String rulesTripped: String totalScore: Int! transactionId: String! } input ErrorInput { error: String message: String } type Error { error: String! message: String! } input ItemInput { classNumber: Int color: String costAmount: Float currentStatus: String department: Int description: String extendedPrice: Float giftWrapped: Boolean groupNumber: Int marginAmount: Float price: Float quantity: Int shippingAddress: AddressInput shippingCountry: String shippingMethod: String signOnDelivery: String size: String skuNumber: Int svsNumber: Int upcNumber: Int } type Item { classNumber: Int color: String costAmount: Float currentStatus: String! department: Int! description: String! extendedPrice: Float! giftWrapped: Boolean groupNumber: Int! marginAmount: Float price: Float! quantity: Int! shippingAddress: Address! shippingCountry: String! shippingMethod: String! signOnDelivery: String size: String skuNumber: Int! svsNumber: Int! upcNumber: Int } input PromoInput { promotionAmount: Float promotionCode: String } type Promo { promotionAmount: Float! promotionCode: String! } input TransactionInput { additionalData: AdditionalDataInput banner: Banner creditCard: CreditCardInput currencyCode: String customer: CustomerInput groupId: String ipAddress: String items: [ItemInput] lastModifiedDate: AWSDate orderId: String orderTotal: Float promos: [PromoInput] salesRep: String shippingCost: Float source: String storeNumber: Int } type Transaction { additionalData: AdditionalData banner: Banner! creditCard: CreditCard! currencyCode: String! customer: Customer! groupId: String! ipAddress: String items: [Item]! lastModifiedDate: AWSDate orderId: String! orderTotal: Float! promos: [Promo] salesRep: String shippingCost: Float! source: String! storeNumber: Int! } enum Banner { BAY LAT O5A S5A } enum CustomerType { EMPLOYEE GUEST REGISTERED } enum RecommendationCode { ACCEPT REJECT REVIEW } schema { query: Query mutation: Mutation } DependsOn: - GqlApi DecisionDataSource: Type: AWS::AppSync::DataSource Properties: ApiId: !GetAtt GqlApi.ApiId LambdaConfig: LambdaFunctionArn: Fn::Join: - '' - - 'arn:aws:lambda:' - !Ref AWS::Region - ':' - !Ref AWS::AccountId - ':function:' - Fn::ImportValue: !Sub '${FunctionStack}-functions-Decision' Name: decision_lambda ServiceRoleArn: !GetAtt DataSourceRole.Arn Type: AWS_LAMBDA DependsOn: - DataSourceRole - GqlApi PostDecisionResolver: Type: AWS::AppSync::Resolver Properties: ApiId: !GetAtt GqlApi.ApiId FieldName: postDecision TypeName: Mutation DataSourceName: !GetAtt DecisionDataSource.Name RequestMappingTemplate: | #set( $cognitoIdentityId = $context.identity.cognitoIdentityId ) #if($context.identity.userArn.matches('arn:aws:iam::\d+:user/.*')) #if($context.args.cognitoIdentityId__) #set( $cognitoIdentityId = $context.args.cognitoIdentityId__ ) #elseif( $context.source.cognitoIdentityId__ ) #set( $cognitoIdentityId = $context.source.cognitoIdentityId__ ) #end #end #set( $unamepwd = "$util.urlEncode($cognitoIdentityId):" ) { "version" : "2017-02-28", "operation": "Invoke", "payload": { "source": "AppSync", "httpMethod": "post", "body": "$util.escapeJavaScript($util.toJson($context.args.decision))", "headers": { "Authorization": "Basic $util.base64Encode($unamepwd)", }, "pathParameters": { }, "queryStringParameters": { } } } ResponseMappingTemplate: | #if($context.result.statusCode >= 200 && $context.result.statusCode <= 299) #set( $result = $util.parseJson($context.result.body) ) #if($context.args.cognitoIdentityId__) #set( $result.cognitoIdentityId__ = $context.args.cognitoIdentityId__ ) #elseif($context.source.cognitoIdentityId__) #set( $result.cognitoIdentityId__ = $context.source.cognitoIdentityId__ ) #end $util.toJson($result) #else $utils.error($util.parseJson($context.result.body).message, $context.result.statusCode.toString(), $util.parseJson($context.result.body)) #end DependsOn: - GqlApi - GqlSchema - DecisionDataSource TransactionDataSource: Type: AWS::AppSync::DataSource Properties: ApiId: !GetAtt GqlApi.ApiId LambdaConfig: LambdaFunctionArn: Fn::Join: - '' - - 'arn:aws:lambda:' - !Ref AWS::Region - ':' - !Ref AWS::AccountId - ':function:' - Fn::ImportValue: !Sub '${FunctionStack}-functions-Transaction' Name: transaction_lambda ServiceRoleArn: !GetAtt DataSourceRole.Arn Type: AWS_LAMBDA DependsOn: - DataSourceRole - GqlApi PostTransactionResolver: Type: AWS::AppSync::Resolver Properties: ApiId: !GetAtt GqlApi.ApiId FieldName: postTransaction TypeName: Mutation DataSourceName: !GetAtt TransactionDataSource.Name RequestMappingTemplate: | #set( $cognitoIdentityId = $context.identity.cognitoIdentityId ) #if($context.identity.userArn.matches('arn:aws:iam::\d+:user/.*')) #if($context.args.cognitoIdentityId__) #set( $cognitoIdentityId = $context.args.cognitoIdentityId__ ) #elseif( $context.source.cognitoIdentityId__ ) #set( $cognitoIdentityId = $context.source.cognitoIdentityId__ ) #end #end #set( $unamepwd = "$util.urlEncode($cognitoIdentityId):" ) { "version" : "2017-02-28", "operation": "Invoke", "payload": { "source": "AppSync", "httpMethod": "post", "body": "$util.escapeJavaScript($util.toJson($context.args.transaction))", "headers": { "Authorization": "Basic $util.base64Encode($unamepwd)", }, "pathParameters": { }, "queryStringParameters": { } } } ResponseMappingTemplate: | #if($context.result.statusCode >= 200 && $context.result.statusCode <= 299) #set( $result = $util.parseJson($context.result.body) ) #if($context.args.cognitoIdentityId__) #set( $result.cognitoIdentityId__ = $context.args.cognitoIdentityId__ ) #elseif($context.source.cognitoIdentityId__) #set( $result.cognitoIdentityId__ = $context.source.cognitoIdentityId__ ) #end $util.toJson($result) #else $utils.error($util.parseJson($context.result.body).message, $context.result.statusCode.toString(), $util.parseJson($context.result.body)) #end DependsOn: - GqlApi - GqlSchema - TransactionDataSource Outputs: ApiEndpoint: Description: The endpoint for the AppSync API. Value: !GetAtt GqlApi.GraphQLUrl