Search code examples
amazon-web-servicesamazon-sqsamazon-snsaws-samaws-api-gateway

AWS SAM + ApiGateway + x-amazon-integration + SNS fifo + SQS fifo: MessageGroupId from path param


I am writing a SAM template for a business application that, among other things, processes device status updates.

Users post status updates to the API Gateway that, in turn, suitably sets the destSQS message attribute and publishes such requests to an SNS topic. Several SQS queues are subscribed to the topic and messages are routed depending on the value of destSQS. The following is the AWS::SNS::Subscription resource definition for the SQS queue of interest for this question.

  StatusUpdatesQueueSubscription: # accept msg iff destSQS is "StatusUpdates"
    Type: AWS::SNS::Subscription
    Properties:
      Endpoint: !Join [ "-", [ !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:${AWS::StackName}", !Ref StatusUpdatesQueueName ] ]
      Protocol: sqs
      FilterPolicy:
        destSQS:
          - "StatusUpdate"
      RawMessageDelivery: True
      TopicArn: !Ref DispatcherSNSTopic

So far everything works with "simple" (i.e., non-FIFO) SNS/SQS. The following is the relevant section of the current OpenAPI (3.0.0) configuration embedded in the SAM template.

/devices/{device_id}/status:  
  post:
    parameters:
      - in: path
        name: device_id
        description: String ID of a device
        required: true
        schema:
          type: string
          description: Device unique identifier
    security:
      - ApiKeyAuth: [ ]
    requestBody:
      description: A status update for a device
      required: true
      content:
        application/json:
          schema:
            type: object            
    responses:
      "202":
        description: Accepted
    x-amazon-apigateway-integration:
      type: "aws"
      httpMethod: "POST"
      uri: !Sub "arn:aws:apigateway:${AWS::Region}:sns:action/Publish"
      credentials: !GetAtt DispatcherSNSTopicAPIRole.Arn
      requestParameters:
        integration.request.querystring.Message: "method.request.body"
        integration.request.querystring.TopicArn: !Sub "'${DispatcherSNSTopic}'"
        integration.request.querystring.MessageAttributes.entry.1.Name: "'destSQS'"
        integration.request.querystring.MessageAttributes.entry.1.Value.DataType: "'String'"
        integration.request.querystring.MessageAttributes.entry.1.Value.StringValue: "'StatusUpdate'"
      responses:
        default:
          statusCode: 202

Now, I want to enrich this configuration to group messages by device_id (so that status updates for the same device will be processed in order).

I've already modified the template Resources section so that SQS queues and the topic are FIFO and tried to add the following mapping:

        integration.request.querystring.MessageAttributes.entry.2.Name: "MessageGroupId"
        integration.request.querystring.MessageAttributes.entry.2.Value.DataType: "'String'"
        integration.request.querystring.MessageAttributes.entry.2.Value.StringValue: method.request.path.device_id

but I get the following error:

   Resource handler returned message: "Errors found during import:
    Unable to put integration on 'POST' for resource at path '/devices/{device_id}/status': Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression specified: MessageGroupId]

What am I missing?


Solution

  • After lots of searches and attempts, I've found the solution. Perhaps sharing is useful for someone in the future.

    1. MessageGroupId has to be set as a child of querystring and not as a MessageAttribute, as follows:
    integration.request.querystring.MessageGroupId: "method.request.path.device_id"
    
    1. the error was due to a syntax error: static strings must be enclosed by single quotes (and possibly, in turn, by double ones)
       integration.request.querystring.MessageAttributes.entry.2.Name: "'MyAttributeName'"