How do I integrate an API Gateway REST API with Amazon SQS and resolve common errors?

5 minute read
0

I want to integrate an Amazon API Gateway REST API with Amazon Simple Queue Service (Amazon SQS), and troubleshoot integration errors.

Resolution

To create an integrated solution, configure API Gateway REST APIs to work with Amazon SQS.

Set up REST API and an Amazon SQS integration

Complete the following steps:

  1. Create an SQS queue.
  2. Create an AWS Identity and Access Management (IAM) role, and then attach an Amazon SQS policy with a SendMessage permission. The policy allows you to publish messages from the API to Amazon SQS:
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Resource": [
            "arn:aws:sqs:example-region:example-account-id:example-sqs-queue-name"
          ],
          "Action": [
            "sqs:SendMessage"
          ]
        }
      ]
    }
    Note: Replace example-region with your AWS Region, example-account-id with your AWS account ID, and example-sqs-queue-name with your SQS queue name.
  3. Create a REST API in API Gateway.
  4. In the API Gateway console, create an Amazon SQS integration for your REST API.
  5. (Optional) Create a REST API resource or a REST API method:
    On the Resources screen, choose Create method.
    For Method type, choose POST.
    For Integration type, choose AWS Service.
    For AWS Region, choose your Region.
    For AWS Service, choose Simple Queue Service (SQS).
    (Optional) For AWS Subdomain, enter the subdomain that the AWS service uses. Check the AWS service documentation to confirm the availability of a subdomain. For the Amazon SQS example setup, keep this blank.
    For HTTP method, choose POST.
    For Action Type, choose Use path override.
    For Path override (optional), enter your account ID and SQS queue name in the following format: example-account-id/example-sqs-queue-name. For example: 1234567890/MySQSStandardQueue.
    For Execution role, enter the ARN of the IAM role.
    For Default Timeout, choose an option for your setup.
    Continue to enter your REST API integration information.
    Choose the POST method Integration Request.
    Choose Edit.
    For Request body passthrough, select the option for your requirements.
    Expand URL request headers parameters.
    Choose Add request header parameter.
    For Name, enter Content-Type.
    For Mapped from, enter 'application/x-www-form-urlencoded'.
    Expand Mapping Templates.
    Choose Add mapping template.
    For Content-Type, enter application/json.
    For the template, enter Action=SendMessage&MessageBody=$input.body, and then choose Save.
  6. Deploy the REST API.
  7. To test the setup, send the following request to API Gateway:
    curl --location --request POST 'https://example-api-id.execute-api.example-region.amazonaws.com/example-stage/example-resource' 
      --header 'Content-Type: application/json' 
      --data-raw '{
        "message": "Hello World"
      }'
    Note: Replace example-api-id with your API ID, example-region with your Region, example-stage with your testing stage name, and example-resource with your resource name.
    When your integration is successful, your response looks similar to the following:
    {
      "SendMessageResponse": {
        "ResponseMetadata": {
          "RequestId": "f879fb11-e736-52c0-bd29-a0f2d09ad90d"
        },
          "SendMessageResult": {
            "MD5OfMessageAttributes": null,
            "MD5OfMessageBody": "3fc759ac1733366f98ec4270c788fcd1",
            "MD5OfMessageSystemAttributes": null,
            "MessageId": "4c360c3c-08f4-4392-bc14-8b0c88e314a2",
            "SequenceNumber": null
        }
      }
    }

Resolve common errors

To troubleshoot common errors, complete the tasks based on the error message that you receive.

UnknownOperationException error

An UnknownOperationException error occurs when you don't configure the Content-Type as "application/x-www-form-urlencoded" in the integration request HTTP header. The UnknownOperationException error also occurs when you don't add the SendMessage action to the integration request mapping template. To resolve this error, make sure that Content-Type is correctly formatted and include the SendMessage action in the mapping template.

AccessDenied error

The following is an example of an AccessDenied error:

{
"Error": {
"Code": "AccessDenied",
"Message": "Access to the resource https://sqs.example-region.amazonaws.com/example-account-id/example-sqs-queue-name is denied.",
"Type": "Sender"
},
"RequestId": "92aea8b7-47f1-5bd4-b3c4-f3d0688d3809" }

An AccessDenied error occurs when the API integration execution role doesn't have the sqs:SendMessage permission set to send messages to the SQS queue. The AccessDenied error can also occur when you pass special characters, such as "&" and "%", in the request body payload. You must encode the special characters to pass. Add the $util.urlEncode() function in the mapping template to convert the request body from a string to an encoded format. The following is an example mapping template:

Action=SendMessage&MessageBody=$util.urlEncode($input.body)

The following example includes the required permissions to send messages to the SQS queue:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Resource": [
        "arn:aws:sqs:example-region:example-account-id:example-sqs-queue-name"
      ],
      "Action": [
        "sqs:SendMessage"
      ]
    }
  ]
}

Note: Replace example-region with your Region, example-account-id with your account ID, and example-sqs-queue-name with your SQS queue name.

KMS.AccessDeniedException error

The following are two examples of KMS.AccessDeniedException errors:

{
"Error": {
"Code": "KMS.AccessDeniedException",
"Message": "User: arn:aws:sts::example-account-number:assumed-role/example-sqs-queue-name/BackplaneAssumeRoleSession is not authorized to perform: kms:GenerateDataKey on resource: arn:aws:kms:example-region:example-account-number:key/example-keyId because no identity-based policy allows the kms:GenerateDataKey action (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: c58f1eec-6b18-4029-826b-d05d6a715716; 
Proxy: null)", 
"Type": "Sender"
},
"RequestId": "99976a6a-3311-57e9-86e9-310d0654ff80"
}

{   
"Error":   {
"Code": "KMS.AccessDeniedException",
"Message": "The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access. (Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID: a8adea02-c246-49d9-8b3d-ff6b6a43b40f;
Proxy: null)",
"Type": "Sender"
},
"RequestId": "9565c451-742c-55f3-a1eb-9f3641fd30aa"
}

A KMS.AccessDeniedException error occurs when the API integration execution role can't perform operations through AWS Key Management Service (AWS KMS). You must configure permissions to perform operations on the AWS KMS keys that are attached to the Amazon SQS server-side encrypted queue.

The following example includes the required permissions to perform operations on the KMS keys that are attached to the SQS queue:

{
  "Sid": "Allow use of the key",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::example-account-id:role/example-api-gw-integration-execution-role"
  },
  "Action": [
    "kms:Encrypt",
    "kms:GenerateDataKey*",
    "kms:Decrypt"
  ],
  "Resource": "*"
}

Note: Replace example-account-id with your account ID and example-api-gw-integration-execution-role with your execution role name.

Related information

Create an API with HTTP custom integration

AWS OFFICIAL
AWS OFFICIALUpdated 16 days ago
5 Comments

is there any way to make this work without overriding path?

MSR
replied 9 months ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
MODERATOR
replied 9 months ago

Hi AWS, is there a way to check the constructed message size does not exceed 256 KiB and directly returning a bad request response using VTL?

Taher
replied 7 months ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
MODERATOR
replied 7 months ago

If you receive this error:

The request must contain the paramter MessageGroupId.

modify your template body to

Action=SendMessage&MessageGroupId=$context.extendedRequestId&MessageBody=$input.body

This provides the unique request ID as the message group ID for SQS. You may also have to enable Content-based deduplication for your SQS queue.

Jeff G
replied 2 months ago