I am trying to build a system where multiple APIs gateway instances should execute the same lambda function.
My problem is that I would like to change only the lambda configuration in function of the API gateway used.
Let's take the name of a database as an example that should change if the lambda is being triggered from one API or the other.
Example:
API Gateways:
https://my-first-api-gateway.execute-api.eu-west-1.amazonaws.com
https://my-second-api-gateway.execute-api.eu-west-1.amazonaws.com
I then have one lambda function being called by the two APIs: say_hello.
This function has to retrieve a quote from a database. If the function has been called from my-first-api-gateway the lambda function has to use my_first_database and if the function has been called from my-second-api-gateway, it has to use my_second_database.
The only solution I came with is to deploy as many lambda functions as I have API Gateways. And then use environment variables to store my database name.
I don't like my solution because when I update a single line of code I'll have to redeploy all of my lambda functions.. (if I have 300 different databases to use, that would mean to update 300 lambda functions at once..)
Thank you for your ideas on this subject!
If you use a Lambda-Proxy integration you should be fine.
Full details of the event can be found here, however critically the headers Host, origin and Referer all point the the API Gateway uri:
"headers": {
"Host": "j3ap25j034.execute-api.eu-west-2.amazonaws.com",
"origin": "https://j3ap25j034.execute-api.eu-west-2.amazonaws.com",
"Referer": "https://j3ap25j034.execute-api.eu-west-2.amazonaws.com/dev/"
}
Therefore it should be fairly trivial for you to branch/look-up your database behaviour from this information.
Related
I'm trying to call a basic lambda from my API Gateway console. The lambda has an input taken in by the event called filterBy.
I created a query string called filterBy however, when I try to invoke the lambda I get the error:
{errorMessage: {'statusCode': 500, 'body': '{"msg": "KeyError(\'filterBy\')"}'}}
Presumably because the piece of code in my lambda
event['filterBy'] is not finding a filterBy in the event. What do I need to do so that I can get the filterBy in the event from the API Gateway console? I understand this is probably quite simple but I surprisingly cannot find anything about this so any help would be appreciated.
Based on the integration type, approach can be vary.
1. Lambda custom integrations:
Looks like you are trying to use Lambda custom integrations. If that is the case you have to add a mapping template as below.
(under the Integration Request -> Mapping Templates --> Add mapping template)
{
"filterBy": "$input.params('filterBy')"
}
Please refer this article or this video for more info.
2. Lambda proxy integrations:
If you are using Lambada proxy integration (either as REST API or as HTTP APIs), then instead of event['filterBy'], you have to access the queryStringParameters first and then access the relevant query param.
event['queryStringParameters']['filterBy']
And another thing is: once you modify something in API GW, please make sure to deploy and wait some time before test. :)
I am currently trying to deploy a Google cloud function using the REST API, in order to listen to a Google cloud storage bucket for changes/deletions.
However, I noticed that I can only specify one EventTrigger
{
"name": string,
"description": string,
"status": enum (CloudFunctionStatus),
"entryPoint": string,
"runtime": string,
...
"sourceUploadUrl": string
// End of list of possible types for union field source_code.
// Union field trigger can be only one of the following:
"httpsTrigger": {
object (HttpsTrigger)
},
"eventTrigger": {
object (EventTrigger)
}
// End of list of possible types for union field trigger.
}
With my options for what to listen to being the following choices
google.storage.object.finalize
google.storage.object.delete
google.storage.object.archive
google.storage.object.metadataUpdate
What if I want to listen to multiple triggers, such as google.storage.object.finalize and google.storage.object.delete, at the same time? Do I need to deploy separate cloud functions for each one? That seems quite inconvenient. Any suggestions or advice would be appreciated.
Yes, you need to deploy multiple functions. Each function can have exactly one trigger.
You could deploy multiple configurations that use the same sources, or use one trigger which has a response to call another function that aggregates different kinds of events.
It can be actually achieved, we do so in our company.
The trick is: put your Cloud Function / Cloud Run as only-authenticated http trigger
Then you get a URL (which only can be touched via authenticated http request).
Then you can both:
Invoke it directly (postman / whatever) if you pass the Bearer token (i.e. get via gcloud auth print-identity-token)
Trigger from pubsub with a PUSH subscription authenticated to that endpoint.
Note that it requires you to give permission from your PubSub subscriber to that resource, but it works! and makes your function/service both sync and async behaviour.
Paul answer is correct if you want to handle only a subset of available events. Or if you want to want to plug directly function on storage events.
However, if you want to catch all, or if you want to choose yourselves in your function the events type to handle, you can 'cheat'.
Indeed, you can publish bucket notification in pubsub, and plug a function on pubsub events.
I have a pretty straightforward stack: API Gateway sitting in front of a lambda. Currently my paths looks something like:
/dogs, /dogs/{id}, etc.
All I want to do is add a version to the base path (i.e. api.dogs.com/v1/dogs). I tried doing this by creating a custom domain name with a base path mapping of v1 pointing to my stage in API Gateway.
This routes just fine through API Gateway but has issues once it hits the routing logic in my lambda. My lambda is expecting /dogs but with the base path mapping the path is actually v1/dogs.
What's a good way to approach this? I want to get away from having to deal with versions directly in my code (lambda) if possible.
In the event object your lambda function receives you should actually find all the needed information with and without versioning:
event = {
"resource": "/hi",
"path": "/v1/hi",
"requestContext": {
"resourcePath": "/hi",
"path": "/v1/hi",
....
},
....
}
Just adjust the code in your router logic to access the desired attributes should fix your problem and remove the need to care about versioning again in your code.
I'm a newbie rails programmer, and I have even less experience with all the AWS products. I'm trying to use lambda to subscribe to and consume an rss feed from youtube. I am able to send the subscription request just fine with HTTParty from my locally hosted rails app:
query = {'hub.mode':'subscribe', 'hub.verify':'sync', 'hub.topic': 'https://www.youtube.com/feeds/videos.xml?channel_id=CHANNELID', 'hub.callback':'API Endpoint for Lambda'}
subscribe = 'HTTParty.post(https://pubsubhubbub.appspot.com/subscribe, :query=>query)
and it will ping the lambda function with a get request. I know that I need to echo back a hub.challenge string, but I don't know how. The lambda event is empty, I didn't see anything useful in the context. I tried formatting the response in the API gateway but that didn't work either. So right now when I try to subscribe I get back a 'Challenge Mismatch' error.
I know this: https://pubsubhubbub.googlecode.come/git/pubsubhubbub-core-0.3.html#subscribing explains what I'm trying to do better than what I just did, and section 6.2.1 is where the breakdown is. How do I set up either the AWS Lambda function and/or the API Gateway to reflect back the 'hub.challenge' verification token string?
You need to use the parameter mapping functionality of API Gateway to map the parameters from the incoming query string to a parameter passed to your Lambda function. From the documentation link you provided, it looks like you'll at least need to map the hub.challenge query string parameter, but you may also need the other parameters (hub.mode, hub.topic, and hub.verify_token) depending on what validation logic (if any) that you're implementing.
The first step is to declare your query string parameters in the method request page. Once you have declared the parameters open the integration request page (where you specify which Lambda function API Gateway should call) and use the "+" icon to add a new template. In the template you will have to specify a content type (application/json), and then the body you want to send to Lambda. You can read both query string and header parameters using the params() function. In that input mapping field you are creating the event body that is posted to AWS Lambda. For example: { "challenge": "$input.params('hub.challenge')" }
Documentation for mapping query string parameters
I have been trying to setup a resource using AWS API Gateway but I can't seem to find a way to either set or access matrix parameters.
I want to be able to set up a resource similar to the following -
GET /image;height=750;width=1000;format=png
Is it possible ?
You need to configure the setup to use Query Parameters.
You do this in the Method Request area of a method configuration from within the console:
https://console.aws.amazon.com/apigateway/home?region=<region-id>#/restapis/<api-id>/resources/<resource-id>/methods/<method-type>
You can also do this use the AWS API Gateway HTTP API putMethod endpoint, or the AWS#APIGateway#putMethod call in any of their SDKs.
API Gateway currently does not support matrix parameters. As a workaround, you could use query parameters as already mentioned and parse them in your backend.
Best,
Jurgen
I realize that this is a very old question. Leaving my response in case someone has a similar challenge
There are multiple ways to set this up. It all comes down to the context in which the API is intended to be used.
While query parameters will solve the problem, they are not the best suited for representing a resource. They fit well with scenarios that involve filtering. If this API is intended to be used as a source for <img /> tags on the UI, this pattern GET .../images/{widthxheight}/{imageName}.{extension} can be used.
Ex: GET .../images/200x400/sponge-bob.png
However, if the intent is for this API to be used for the purpose of looking up. the below definition can be used -
POST .../image-results
Content-Type: application/json
{
"name":"sponge bob",
"height": 400,
"width": 200,
"format": "png"
}