Pass query string parameters from WSO2 api gateway to AWS lambda - aws-lambda

I need to pass query string parameters calling a WSO2 api gateway that calls an AWS lambda function.
I created the following lambda function in NodeJS in AWS:
exports.handler = async (event, context) => {
return {
statusCode: 200,
body: JSON.stringify({
incoming:JSON.parse(event),
date: new Date(),
context: JSON.parse(context)
}),
};
};
Then I:
created a new API in wso2 publisher portal
added an endpoint of type lambda
configured a resource getTest for GET
added a query parameter parameter to the GET resource
When I call my API here is the result:
curl -X GET "https://localhost:8243/lambda/1/getTest?parameter=myValue" -H "accept: */*" -H "Authorization: Basic YWRtaW46YWRtaW4="
{
"statusCode":200,
"body":"{\"incoming\":{},\"date\":\"2021-06-22T08:09:36.027Z\",\"context\":{\"callbackWaitsForEmptyEventLoop\":true,\"functionVersion\":\"$LATEST\",\"functionName\":\"wso2get\",\"memoryLimitInMB\":\"128\",\"logGroupName\":\"/aws/lambda/wso2get\",\"logStreamName\":\"2021/06/22/[$LATEST]90a7f95746c644a7a5cc61ec8648228e\",\"invokedFunctionArn\":\"arn:aws:lambda:eu-west-1:659641230079:function:wso2get\",\"awsRequestId\":\"4e271442-6209-47d9-ab0c-277c6535b8bd\"}}"
}
How can I retrieve the parameter with value myValue in the lambda function?

You have to define you OpenAPI definition with this two kind of parameters:
Path Parameter
Query Parameter
I'll use wso2apim 2.6.0 and OpenAPI 2.0 definition...
Go to the /publisher and "Add a new API" with the "Design a New REST API"
Add a name , a contest ( ex. /mylambda ), and so on.
In the "API Definition" include a URL Pattern like
"/{id}/getTest" and check de GET method. Automatically a "Path parameter" is added with name "id".
Then add a new parameter named "parameter"
Save and in the implementation, set the "Endpoints" set the URL to:
"https://localhost:8243/lambda"
And that's all.

This is fixed in the latest pack. You can send path/query/header parameters, http method, and path along with the payload to Lambda. Make sure you define the parameter names at resource creation time as in 8.b.iii in [1]. Following is the format of the event object which Lambda receives.
{
"headers": {},
"pathParameters": {},
"queryStringParameters": {},
"body": {},
"httpMethod": "",
"path": ""
}
Note that, to enable param mapping for earlier versions, you have to put following config to deployment.toml file.
[apim.lambda_mediator_config]
pass_request_params = true
[1] https://apim.docs.wso2.com/en/latest/design/create-api/create-rest-api/create-a-rest-api/

Related

No value in FHIR extensions

I have a C# REST API that uses the Hl7.Fhir.R4 library (3.7.0) with a POST method that receives an object of type Hl7.Fhir.Model.Patient:
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[HttpPost()]
public async Task<IActionResult> Post(Patient patient)
{
IActionResult status = NotFound();
...
}
The Patient object has a list of extensions:
"extension": [
{
"url": "http://example.com/fhir/extension/patient/origin",
"valueString": "test"
},
{
"url": "http://example.com/fhir/extension/patient/domainId",
"valueInt" : "10"
}...
When receiving the JSON as a parameter in the POST function, all the fields have a better value than those of type 'Hl7.Fhir.Model.DataType':
Extension[0]
Children: {Hl7.Fhir.Model.Extension.<get_Children>d__17}
ElementId: null
NamedChildren: {Hl7.Fhir.Model.Extension.<get_NamedChildren>d__19}
Extension: Count = 0
TypeName: "Extension"
Url: "http://example.com/fhir/extension/patient/origin"
Value: null
Am I missing some decorator or attribute or simply can't the object be directly deserialized?
Did you use the FhirJsonParser from the library to parse the data? You cannot use a regular JSON parser, because it will not be able to handle the FHIR model correctly.
ETA:
As you now mention in your question, the object cannot be directly deserialized, see first part of my response.
Maybe you can take a look at this project to see how it's done there: https://github.com/brianpos/fhir-net-web-api

How to pass the validation code to the Lambda function

I'm trying to customize the email that AWS Cognito sends if a user has forgotten their password.
It requires {####} placeholder for the verification code in the email message. For example, if you do
event['response']['emailMessage'] = "Your code is {####}", you'll receive a message Your code is 123456.
Here's an example of my AWS Lambda function:
def custom_message_handler(event, context):
event['response']['emailSubject'] = 'Custom subject'
event['response']['emailMessage'] = 'Custom email'
# verification_code = event[...] ???
return event
It seems like Cognito generates the verification code after your lambda returned the message with the placeholder. Is it possible to get the verification code inside your lambda to use it?
Amazon Cognito's Custom Message Lambda Trigger's Event JSON does not get the numerical verification code. The data of the Event available to the trigger, as stated in the official documentation is stated as follows:
{
"version": 1,
"triggerSource": "CustomMessage_AdminCreateUser",
"region": "<region>",
"userPoolId": "<userPoolId>",
"userName": "<userName>",
"callerContext": {
"awsSdk": "<calling aws sdk with version>",
"clientId": "<apps client id>",
...
},
"request": {
"userAttributes": {
"phone_number_verified": false,
"email_verified": true,
...
},
"codeParameter": "####",
"usernameParameter": "username"
},
"response": {
"smsMessage": "<custom message to be sent in the message with code parameter and username parameter>"
"emailMessage": "<custom message to be sent in the message with code parameter and username parameter>"
"emailSubject": "<custom email subject>"
}
}
You would be able to use Cognito data in a Lambda trigger only if it is available in an Event, or if there is a separate API call for the same. But given Amazon Cognito's design, this does not seem to be possible.

Programmatically get Account Id from lambda context arn

I have access to
com.amazonaws.services.lambda.runtime.Context;
object and by extension the invoked function Arn. The arn contains the account Id where the lambda resides.
My question is simple, I want the cleanest way to extract the account Id from that.
I was taking a look
com.amazon.arn.ARN;
It has a whole bunch of stuff, but no account ID (which i presume is due to the fact that not all arns have account ids ?)
I want to cleanly extract the account Id, without resorting to parsing the string.
If your lambda is being used as an API Gateway proxy lambda, then you have access to event.requestContext.accountId (where event is the first parameter to your handler function).
Otherwise, you will have to split the ARN up.
From the AWS documentation about ARN formats, here are the valid Lambda ARN formats:
arn:aws:lambda:region:account-id:function:function-name
arn:aws:lambda:region:account-id:function:function-name:alias-name
arn:aws:lambda:region:account-id:function:function-name:version
arn:aws:lambda:region:account-id:event-source-mappings:event-source-mapping-id
In all cases, account-id is the 5th item in the ARN (treating : as a separator). Therefore, you can just do this:
String accountId = arn.split(":")[4];
You no longer need to parse the arn anymore, sts library has introduced get_caller_identity for this purpose.
Its an overkill, but works!.
Excerpts from aws docs.
python
import boto3
client = boto3.client('sts')
response = client.get_caller_identity()['Account']
js
/* This example shows a request and response made with the credentials for a user named Alice in the AWS account 123456789012. */
var params = {
};
sts.getCallerIdentity(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
/*
data = {
Account: "123456789012",
Arn: "arn:aws:iam::123456789012:user/Alice",
UserId: "AKIAI44QH8DHBEXAMPLE"
}
*/
});
More details here & here
I use this:
ACCID: { "Fn::Join" : ["", [{ "Ref" : "AWS::AccountId" }, "" ]] }
golang
import (
"github.com/aws/aws-lambda-go/lambdacontext"
)
func Handler(ctx context.Context) error {
lc, ok := lambdacontext.FromContext(ctx)
if !ok {
return errors.Errorf("could not get lambda context")
}
AwsAccountId := strings.Split(lc.InvokedFunctionArn, ":")[4]

No handler found for uri [/<index>/<type>/] and method [PUT]

I'm trying to make a raw NodeJS http request to my elasticsearch index using the insert document api's auto increment id feature.
So this works with curl:
curl -XPOST http://host:3333/catalog/products -d '{ "hello": "world" }'
But when I try the same in nodejs via this:
var http = require('http');
var options = {
protocol: 'http:',
mehtod: 'PUT',
hostname: 'host',
port: 3333,
path: '/catalog/products/'
}
http.request(options, ...);
It returns this error:
No handler found for uri [/catalog/products/] and method [PUT]
However if I add an id to the end of that path it will work. What's wrong here?
The problem here is the way POST and PUT works, when you use POST, _id is optional, ES will generate a unique _id for you every time.
Here you are using PUT so _id is required, ES will either create a new document with that id or it will update the document with that id if it exists. You can read more about this.
Try indexing with POST request as you did with curl if you dont want to specify id
var options = {
protocol: 'http:',
hostname: 'host',
port: 3333,
path: '/catalog/products/',
method: 'POST' <--- specify method
}
Hope this helps!

How to do POST request to Grape REST API using params block compatible with Swagger

I am using grape to build a REST API, I am having some trouble with params options.
This is how I do a POST request:
# Curl Request
# curl -X POST -H "Content-Type:application/json" 0:9292/v1/articles -d '{"title":"hello","body":"world"}'
# {"error":"article is missing"}
# curl -X POST -H "Content-Type:application/json" 0:9292/v1/articles -d '{"article":{title":"hello","body":"world"}}'
# {"error":"article is invalid"}
As you can see if I omit article it fails article missing, If i put article and it fails article invalid.
This is the code, I am using grape-entity.
# Entity
module API
module Entities
class Article < Grape::Entity
expose :title, documentation: { type: 'string', desc: 'Title' }
expose :body, documentation: { type: 'string', desc: 'Body' }
end
end
end
# API
desc "Create an article"
params do
requires :article, type: API::Entities::Article, documentation: { eg: "aklsdfj" }
end
post '/articles' do
puts params
article = Article.create(params(:title, :body))
represent(article, env)
end
# Add Swagger Docs
add_swagger_documentation mount_path: 'api/doc',
api_version: 'v1',
markdown: GrapeSwagger::Markdown::KramdownAdapter,
hide_documentation_path: true,
base_path: Application.config.base_path,
models: [API::Entities::Article]
Specifically the problem is caused by params block, it requires an :article of type API:Entities::Article.
Also note that, I am using add-swagger-documentation, and this code
produces correct swagger documentation, so the solution have to be
fully compatible with swagger. What is the correct usage of params
block without offending the swagger.
I'm not sure what you're trying to accomplish here. I guess you want to change your post method in a way that it accepts a JSON like this:
{ attribute1: value, attribute2: value }
instead of
{ article: { attribute1: value, attribute2: value } }
In this case, you have to change your params block to something like this
params do
requires :attribute1, type: String, documentation: { eg: "aklsdfj" }
requires :attribute2, type: String, documentation: { eg: "aklsdfj" }
end
instead of
params do
requires :article, type: API::Entities::Article, documentation: { eg: "aklsdfj" }
end
The params block above is expecting a JSON containing an article attribute composed by every attribute defined in the entity API::Entities::Article.
In fact, Grape doesn't accept entity objects as a type for a parameter.

Resources