Home > Software design >  AWS Api Gw, Sqs, Lambda
AWS Api Gw, Sqs, Lambda

Time:08-16

Is there a way where I can have a set-up of API Gateway -> SQS -> Lambda? Having Lambda return an API Gateway response to the client-side. I already have API Gateway -> SQS. The Lambda function will be triggered if there is a queue in SQS. The only problem is, how can I have my Lambda return an API Gateway response to the client-side?

SQS

const sqs = new sqs.Queue(this, 'sqs', {
   visibilityTimeout: cdk.Duration.seconds(60),
   queueName: 'sqs',
 });
sqs.grantSendMessages(customRole);

const sqsIntegration = new apigw.AwsIntegration({
   service: 'sqs',
   integrationHttpMethod: "POST",
   path: `${cdk.Aws.ACCOUNT_ID}/${sqs.queueName}`,
   options: {
     credentialsRole: customRole,
     passthroughBehavior: apigw.PassthroughBehavior.NEVER,
     integrationResponses: [def.IntegrationResponse(200)],
     requestParameters: {
       'integration.request.header.Content-Type': `'application/x-www-form-urlencoded'`,
     },
     requestTemplates: {
       "application/json": `Action=SendMessage&MessageBody=\{\"route\"\: \"$input.params('route')\", \"seat\"\: \"$input.params('seat')\", \"body\"\: \"$util.parseJson($input.body)\"\}`
     }
   }
});

Lambda

const lambdaFn = new lambda.Function(this, 'lambdaFn', {
   functionName: 'lambdaFn',
   handler: 'lambdaFn',
   memorySize: 1024,
   role: customRole,
   runtime: lambda.Runtime.GO_1_X,
   timeout: cdk.Duration.seconds(60),
   code: lambda.Code.fromAsset('cmd/lambdaFn')
});

lambdaFn.addEventSource(new SqsEventSource(sqs, {
   enabled: true
}));

API GW Method

apigw.addMethod('POST', sqsIntegration, {
   requestParameters: {
     'method.request.querystring.seat': true,
     'method.request.querystring.route': true
   },
   methodResponses: [
     def.MethodResponse(200, ApiResponseModel),
     def.MethodResponse(400, ApiResponseModel),
     def.MethodResponse(415, ApiResponseModel),
   ],
   requestValidatorOptions: {
     validateRequestBody: false,
     validateRequestParameters: true,
     requestValidatorName: 'api-sqs-validator',
   }
});

CodePudding user response:

No, it is not possible.

The API Gateway integrates with a ton of services.
And when it does that it integrates using HTTP.
HTTP integrations are stateful, in the sense that it sends a request and wait for a response.

Your current implementation sends a request to API Gateway.
When API Gtw receives the request, it accepts the connection from the client.
It keeps the connection open while it creates a new connection between API Gtw and SQS.

When SQS sends back a response, API Gtw closes the connection with SQS, sends the client the configured response, and closes the connection with the client.

Later in time, Lambda creates a new connection with SQS and read the available messages.
At this moment, the connection between the client and the API Gtw does not exist anymore.
The only way to make it work would be for the Lambda Function to create a new connection between the function and the client.

But you're missing something here.
You can not connect the Lambda that reads from SQS to your client because you're using an asynchronous pattern.
And this pattern was designed to avoid your client have a direct connection to your running code (Lambda Function).

To solve your issue, you can modify your implementation to use a synchronous pattern (Client -> API Gtw -> Lambda -> API Gtw -> Client) or you can use one of the multiple choices to get the response, like for example, the Asynchronous Request-Reply Pattern.

CodePudding user response:

I don't think you can establish such a synchronous flow from client with SQS in the middle. For instance, how would the client receive the response from the Lambda, if the SQS message is processed multiple times from the queue (with standard queues you get the at-least-once delivery)?

Only thing I could think of how you could enable responding from Lambda to client is via websockets. Then you could establish a duplex communication channel between the client & lambda. But even then, you need to consider the boundaries set by the SQS queue.

  • Related