LocalStack is neat, but it's hard to find documentation for it. I'm having trouble hitting my API Gateway proxy endpoint that's connected to a Lambda function.
The only things I can think of is when I did the put-integration for the gateway, I wasn't sure how to handle the credentials param (given this is 100% local... there's no real AWS account I'm using) so I left it commented for now:
aws --endpoint-url=http://localhost:4567 apigateway \
put-integration \
--region us-west-2 \
--rest-api-id 0091232159 \
--resource-id 3732709762 \
--http-method ANY \
--type AWS_PROXY \
--integration-http-method POST \
--uri arn:aws:lambda:us-west-2:000000000000:function:PostProposal \
#--credentials arn:aws:iam::123456789012:role/apigAwsProxyRole
And my coworker found a thread that make it sound like maybe it's a bug in LocalStack:
https://github.com/atlassian/localstack/issues/129
Anyway, here's what my API looks like when I do aws --endpoint-url=http://localhost:4567 apigateway get-resources --rest-api-id 0091232159
:
{
"items": [
{
"id": "3312801A-ZA-Z6",
"path": "/",
"resourceMethods": {
"GET": {}
}
},
{
"id": "3732709762",
"parentId": "3312801A-ZA-Z6",
"pathPart": "{proxy+}",
"path": "/{proxy+}",
"resourceMethods": {
"GET": {},
"ANY": {
"httpMethod": "ANY",
"authorizationType": "NONE",
"methodIntegration": {
"type": "AWS_PROXY",
"httpMethod": "ANY",
"uri": "arn:aws:lambda:us-west-2:000000000000:function:PostProposal",
"integrationResponses": {
"200": {
"statusCode": 200,
"responseTemplates": {
"application/json": null
}
}
}
}
}
}
}
]
}
My Lambda function is all set up and responds with a 200 when I do:
aws --endpoint-url=http://localhost:4574 lambda invoke --function-name PostProposal outfile.json
Now I just want to cURL an endpoint that will fire off the Lambda.
I found this thread: https://github.com/localstack/localstack/issues/229 which has a cURL example:
curl http://localhost:4567/restapis/35937034A-Z3/test/_user_request_/u-1234
And another one: https://bitbucket.org/atlassian/localstack/issues/4/how-to-create-api-gateway-deployments which has:
curl http://localhost:4567/restapis/$api_id/v1/_user_request_/mypath
I know my API ID and that 'v1' correlates to my 'test' stage name. My endpoint is at the root, so I don't think I need something where he's got bypath.
So I've tried all different variations of paths like this with GET and POST:
curl http://localhost:4567/restapis/0091232159/test/_user_request_/
I get various replies of 404, 500, and {"message": "Unable to find integration for path ...
.
I'm at least hitting the API Gateway simulated server; when I do curl -vv I see:
* Connected to localhost (127.0.0.1) port 4567 (#0)
> GET /restapis/0091232159/test/_user_request_/ HTTP/1.1
> Host: localhost:4567
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 404 Not Found
Any ideas? I just need the magic path!
The backend Lambda function parses the incoming request data to determine the response that it returns. For API Gateway to pass the Lambda output as the API response to the client, the Lambda function must return the result in this format.
You can use AWS SDKs or AWS CLI to enable cross-account access for a Lambda function to be used as Lambda authorizer and Integrations in Amazon API Gateway.
To pass custom headers from an API Gateway API to a Lambda function, use a body mapping template. The API sends the updated API request to a Lambda function to process the headers. Then, the Lambda function returns one or more header values from the original API request.
Did you deploy your API? I don't see the command for that above. If yes, it should be visibile if you open http://localhost:4567/restapis in your browser.
Just to be sure, here is a complete walkthrough for setting up a lambda with API Gateway in Localstack:
First we create a simple NodeJS Lambda:
const apiTestHandler = (payload, context, callback) => {
console.log(`Function apiTestHandler called with payload ${JSON.stringify(payload)}`);
callback(null, {
statusCode: 201,
body: JSON.stringify({
somethingId: payload.pathParameters.somethingId
}),
headers: {
"X-Click-Header": "abc"
}
});
}
module.exports = {
apiTestHandler,
}
Put that into a zip File called apiTestHandler.zip and upload it to localstack:
aws lambda create-function \
--region us-east-1 \
--function-name api-test-handler \
--runtime nodejs6.10 \
--handler index.apiTestHandler \
--memory-size 128 \
--zip-file fileb://apiTestHandler.zip \
--role arn:aws:iam::123456:role/role-name --endpoint-url=http://localhost:4574
Now we can create our Rest-Api:
aws apigateway create-rest-api --region us-east-1 --name 'API Test' --endpoint-url=http://localhost:4567
This gives the following response:
{
"name": "API Test",
"id": "487109A-Z548",
"createdDate": 1518081479
}
With the ID we got here, we can ask for its parent-ID:
aws apigateway get-resources --region us-east-1 --rest-api-id 487109A-Z548 --endpoint-url=http://localhost:4567
Response:
{
"items": [
{
"path": "/",
"id": "0270A-Z23550",
"resourceMethods": {
"GET": {}
}
}
]
}
Now we have everything to create our resource together with its path:
aws apigateway create-resource \
--region us-east-1 \
--rest-api-id 487109A-Z548 \
--parent-id 0270A-Z23550 \
--path-part "{somethingId}" --endpoint-url=http://localhost:4567
Response:
{
"resourceMethods": {
"GET": {}
},
"pathPart": "{somethingId}",
"parentId": "0270A-Z23550",
"path": "/{somethingId}",
"id": "0662807180"
}
The ID we got here is needed to create our linked GET Method:
aws apigateway put-method \
--region us-east-1 \
--rest-api-id 487109A-Z548 \
--resource-id 0662807180 \
--http-method GET \
--request-parameters "method.request.path.somethingId=true" \
--authorization-type "NONE" \
--endpoint-url=http://localhost:4567
We are almost there - one of the last things to do is to create our integration with the already uploaded lambda:
aws apigateway put-integration \
--region us-east-1 \
--rest-api-id 487109A-Z548 \
--resource-id 0662807180 \
--http-method GET \
--type AWS_PROXY \
--integration-http-method POST \
--uri arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:000000000000:function:api-test-handler/invocations \
--passthrough-behavior WHEN_NO_MATCH \
--endpoint-url=http://localhost:4567
Last but not least: Deploy our API to our desired stage:
aws apigateway create-deployment \
--region us-east-1 \
--rest-api-id 487109A-Z548 \
--stage-name test \
--endpoint-url=http://localhost:4567
Now we can test it:
curl http://localhost:4567/restapis/487109A-Z548/test/_user_request_/HowMuchIsTheFish
Response:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 34 100 34 0 0 9 0 0:00:03 0:00:03 --:--:-- 9
{"somethingId":"HowMuchIsTheFish"}
I hope this helps.
Hint 1: For easier use I recommend to install AWSCLI Local ( https://github.com/localstack/awscli-local ) - with this tool you can use the command "awslocal" and don't have to type "--endpoint-url= ..." for each command
Hint 2: If you don't want to define the above steps manually each time in the future I recommend the use of the Serverless Framework ( https://serverless.com/ ) together with the localstack plugin ( https://github.com/temyers/serverless-localstack ). If you need help with that I can provide you with a short guide as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With