SQS and API Gateway can talk directly, bypassing Lambda entirely.

Let’s see how this actually works. Imagine we have a simple API endpoint /send that accepts POST requests. Instead of a Lambda function processing this request, we want API Gateway to take the incoming request body and push it directly onto an SQS queue.

Here’s a sample serverless.yml configuration to achieve this:

service: sqs-direct-integration

provider:
  name: aws
  runtime: nodejs18.x # Still needed for IAM role creation, even if no function code
  region: us-east-1
  iam:
    role:
      statements:
        - Effect: "Allow"
          Action:
            - "sqs:SendMessage"
          Resource: !GetAtt MyQueue.Arn

functions:
  # No actual function code here, just a placeholder for IAM role generation
  # The API Gateway integration will be configured separately.
  # If you don't have any functions, you might need a minimal function
  # or adjust IAM role creation strategy if your provider doesn't auto-generate.
  # For Serverless Framework, this is a common pattern.
  dummy:
    handler: handler.dummy # This file won't be deployed or executed

resources:
  Resources:
    MyQueue:
      Type: AWS::SQS::Queue
      Properties:
        QueueName: my-direct-integration-queue

    ApiGatewayRestApi:
      Type: AWS::ApiGateway::RestApi
      Properties:
        Name: SQSDirectIntegrationAPI

    ApiGatewayResource:
      Type: AWS::ApiGateway::Resource
      Properties:
        RestApiId: !Ref ApiGatewayRestApi
        ParentId: !GetAtt ApiGatewayRestApi.RootResourceId
        PathPart: send

    ApiGatewayMethod:
      Type: AWS::ApiGateway::Method
      Properties:
        RestApiId: !Ref ApiGatewayRestApi
        ResourceId: !Ref ApiGatewayResource
        HttpMethod: POST
        AuthorizationType: NONE
        Integration:
          Type: AWS
          IntegrationHttpMethod: POST # The HTTP method for the AWS service integration
          Uri: !Join
            - ""
            - - "arn:aws:apigateway:"
              - !Ref AWS::Region
              - ":sqs:action/aws-apigateway/send/service/sqs/action/SendMessage" # Custom integration URI
          Credentials: !GetAtt ApiGatewayRole.Arn # Role API Gateway assumes to send to SQS
          RequestParameters:
            integration.request.header.X-Amz-Target: "'SendMessage'" # Needed for SQS action
            integration.request.header.X-Amz-Content-Type-X: "'application/x-amz-json-1.0'" # Also needed for SQS action
            integration.request.path.QueueUrl: !Ref MyQueue # Dynamically set QueueUrl
            integration.request.body.MessageBody: "integration.request.body" # Map request body to MessageBody

    ApiGatewayDeployment:
      Type: AWS::ApiGateway::Deployment
      Properties:
        RestApiId: !Ref ApiGatewayRestApi
        StageName: prod

    ApiGatewayRole:
      Type: AWS::IAM::Role
      Properties:
        AssumeRolePolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Effect: "Allow"
              Principal:
                Service:
                  - "apigateway.amazonaws.com"
              Action:
                - "sts:AssumeRole"
        Policies:
          - PolicyName: "ApiGatewaySQSSendMessagePolicy"
            PolicyDocument:
              Version: "2012-10-17"
              Statement:
                - Effect: "Allow"
                  Action:
                    - "sqs:SendMessage"
                  Resource: !GetAtt MyQueue.Arn

When you deploy this, API Gateway will create a REST API with a /send resource that accepts POST requests. The ApiGatewayMethod resource is where the magic happens.

The Integration block defines how API Gateway connects to other AWS services.

  • Type: AWS tells API Gateway this is an AWS service integration.
  • IntegrationHttpMethod: POST is the HTTP method API Gateway will use to call the SQS service endpoint.
  • Uri is a special string that tells API Gateway which service action to perform. For SQS SendMessage, it’s arn:aws:apigateway:REGION:sqs:action/aws-apigateway/send/service/sqs/action/SendMessage. This is a built-in API Gateway integration URI.
  • Credentials points to an IAM role that API Gateway will assume to perform the sqs:SendMessage action. This role needs sqs:SendMessage permissions for your specific queue.
  • RequestParameters is crucial. It maps incoming request details to parameters required by the SQS SendMessage API.
    • integration.request.header.X-Amz-Target: "'SendMessage'": This header tells SQS which API action to invoke.
    • integration.request.header.X-Amz-Content-Type-X: "'application/x-amz-json-1.0'": Specifies the content type for the JSON payload.
    • integration.request.path.QueueUrl: !Ref MyQueue: This dynamically injects the SQS queue URL into the integration request.
    • integration.request.body.MessageBody: "integration.request.body": This is the core mapping. It takes the entire body of the incoming HTTP POST request and assigns it to the MessageBody parameter of the SQS SendMessage API call.

The ApiGatewayRole is a separate IAM Role that API Gateway assumes. It must have sqs:SendMessage permissions on the target queue. The Provider section in serverless.yml (or explicit IAM resource definition) ensures the necessary IAM policies are attached to the role that API Gateway will use.

After deployment, you can send a POST request to your API Gateway endpoint. For example, using curl:

curl -X POST \
  https://<your-api-id>.execute-api.us-east-1.amazonaws.com/prod/send \
  -H 'Content-Type: application/json' \
  -d '{
    "orderId": "12345",
    "item": "widget",
    "quantity": 10
  }'

The serverless.yml above will create the SQS queue (MyQueue), the API Gateway REST API (ApiGatewayRestApi), the /send resource (ApiGatewayResource), the POST method (ApiGatewayMethod), the deployment (ApiGatewayDeployment), and the necessary IAM role for API Gateway (ApiGatewayRole).

The most surprising thing is how the Uri and RequestParameters work together to abstract away the direct SDK call. API Gateway is essentially acting as a proxy that translates HTTP requests into AWS service API calls based on these configurations.

If you inspect the SQS queue (my-direct-integration-queue) in the AWS console, you’ll see a message with the JSON body you sent via curl. There was no Lambda execution involved.

The next thing you’ll likely run into is needing to process these messages. That’s where SQS event source mapping for Lambda or SQS consumers come into play.

Want structured learning?

Take the full Sqs course →