I am trying to create a API/Lambda process which takes a comment and posts in into my RDS Aurora database.
The comment field in the database is set as TEXT type
The lambda function posts the comment to the database
The API method is POST
A mapping template has been set u to map the request body into the lambda function
All work perfectly until I start to try and post large comments. (A large paragraph, maybe 500 characters)
The body looks as follows:
{
"comment":"long comment"
}
When I run it in Lambda, I can post massive comments, however when I try and do it through the API Gateway I get an error
Endpoint response body before transformations: {"stackTrace": [["/var/task/app.py", 38, "handler", "raise Exception('Internal Error: Unable to post the comment.')"]], "errorType": "Exception", "errorMessage": "Internal Error: Unable to post the comment."}
I would suggest to use the test invoke feature on API Gateway console. From there, you can see the payload before transformed and after transformed. That might be a bit on debugging.
Related
We are migrating our APIs from unversioned to versioned, and having an issue while trying to get assets data from creatives endpoint.The response has reference to a post, but we are unable to use the expand URNs concept and get the inner media details of the Post URN. Is there a different approach we need to follow here?
I've read through all the migration documents and the response decoration document is also pointing to v2 endpoint and projection parameters, instead of using rest endpoint and fields parameter. Document reference.
Previous Request
GET -
https://api.linkedin.com/v2/adCreativesV2?ids[0]=181794673&projection=(results(*(variables(data(com.linkedin.ads.SponsoredVideoCreativeVariables(userGeneratedContentPost~(specificContent(com.linkedin.ugc.ShareContent(shareCommentary,media(*(media~:playableStreams(),title)))))))))))
This request gets us the media details of the creatives without making multiple calls.
Current Request
GET - https://api.linkedin.com/rest/creatives?ids=List(urn%3Ali%3AsponsoredCreative%3A181794673)&fields=(results(*(content(reference~($URN)))))
I am looking at the response I got from https://api.linkedin.com/rest/creatives?ids=List(urn%3Ali%3AsponsoredCreative%3A181794673) and trying to create the fields request. But no luck yet and getting the below error.
{
"status": 400,
"code": "ILLEGAL_ARGUMENT",
"message": "Invalid projection parameter: (results(*(content(reference~($URN)))))"
}
But when tried with projection in place of fields I got a response
{
"results": {
"urn:li:sponsoredCreative:181794673": {
"content": {
"reference": "urn:li:ugcPost:6905584391779950593",
"reference!": {
"message": "Not enough permissions to access deco: ugcPosts.BATCH_GET.20230101",
"status": 403
}
}
}
}
}
Can someone help me getting the data similar to how we got it before, without making external calls? Otherwise I think I have to be making calls to Creatives -> Posts -> Video, Image, Share etc endpoints
I am trying to make a post request via R using the httr package to composer rest server. I have written a code and then created the composer rest server from it. These are my details
Request URL : http://localhost:3000/api/nl.amis.registry.fruits
Body: {
"$class": "nl.amis.registry.fruits",
"Id": "9",
"name": "orange",
"description": "string",
"count": ""
}
First, I have tried with the composer rest server. For my purpose, I needed the count to be blank and the value will be appended by another API call. I was able to make the transaction successfully with the count: "". This I was able to check in the test section of the composer playground. The remaining code works fine which appends the count variable later on.
Now I am writing an R code to make a similar transaction through POST request. Here I am facing an error that "count cannot be blank" and returns with error 422 Unprocessable entity. The content type I was used was application/json. While using the "count":{} , the post request process fine and i am getting "count":[object Object] in the response. But the later on code which does the appending will do something like count:"[object Object],1" wherein I am expecting "count":"1". Everything works fine while using the test in composer playground but while trying to access externally via rest API is creating the problem. Please help.
you can use an Optional keyword to declare a count in an asset of the model file. using Optional keyword you can post an empty value of count.
for example:
asset fruits identified by Id {
o String Id
o String name
o String description
o String count optional
}
I am trying to call an API from an ejabberd (17.04) module from erlang code by making a Post request. The API is called successfully, however, the data in the request body gets truncated.
Following is my erlang code to make the POST request.
Data = string:join(["to=", binary_to_list(To), "&from=", binary_to_list(From), "&body=", Body], ""),
Request = {binary_to_list(PostUrl), [{"Authorization", binary_to_list(Token)}], "application/x-www-form-urlencoded", Data},
httpc:request(post, Request,[],[]),
I pass the data with the application/x-www-form-urlencoded content type.
There is no error while compiling or running the code, however, if there are some special characters in the Body variable, then the data is not sent to the API.
For example, when the Body variable contains the following value:
{xmlel,<<\"encrypted\">>,\n [{<<\"xmlns\">>,<<\"eu.siacs.conversations.axolotl\">>}],\n [{xmlel,<<\"header\">>,\n [{<<\"sid\">>,<<\"344245169\">>}],\n [{xmlel,<<\"key\">>,\n [{<<\"rid\">>,<<\"684863397\">>}],\n [{xmlcdata,<<\"MwohBTL6tSWIPtugiO0qo0RNrWFC3ypIL5JpwMN1qF8jAoQ1EAAYASIwKnIw/zo43lF4At93Q7PMePlDVGF47Hf6xIvSjm+bpcESskndwFudirxigLSqc6J/P0IEL3sErsE=\">>}]},\n {xmlel,<<\"iv\">>,[],\n [{xmlcdata,<<\"JR7NorYN19NBDwyY3eqXcg==\">>}]}]},\n {xmlel,<<\"payload\">>,[],\n [{xmlcdata,<<\"Da1s4qj6MiPgE1CP9S1ou5Cod//QAfmguc5GUGEk7IfTUJ8VU9CvL6iOfI3qK6Rg7uVNWACTWKBqCWGQstBkEEkwLDZHzJBqoJ6CoE4vxyfEdowWLqt84fNhGcsgvVxqmEDIln0NA2gDRd/vhGi0yIh2JdMQ55+6Ten1+fVb+kwYlKxe94XyMV84Yiz+bfPkAach22oYCZyMx695JSBnaUb8MRLISlnkcpLv/UJtmEMlGER/t5Ac5BK00sbkbVo4zOMbfOgA++prt4mbpceTGyJpmkRa/75xoqDPbYxG3sYujq52RguW1YO649M=\">>}]}]}
The Data variable contains the following value:
"to=186&from=274&body={xmlel,<<\"encrypted\">>,\n [{<<\"xmlns\">>,<<\"eu.siacs.conversations.axolotl\">>}],\n [{xmlel,<<\"header\">>,\n [{<<\"sid\">>,<<\"344245169\">>}],\n [{xmlel,<<\"key\">>,\n [{<<\"rid\">>,<<\"684863397\">>}],\n [{xmlcdata,<<\"MwohBTL6tSWIPtugiO0qo0RNrWFC3ypIL5JpwMN1qF8jAoQ1EAAYASIwKnIw/zo43lF4At93Q7PMePlDVGF47Hf6xIvSjm+bpcESskndwFudirxigLSqc6J/P0IEL3sErsE=\">>}]},\n {xmlel,<<\"iv\">>,[],\n [{xmlcdata,<<\"JR7NorYN19NBDwyY3eqXcg==\">>}]}]},\n {xmlel,<<\"payload\">>,[],\n [{xmlcdata,<<\"Da1s4qj6MiPgE1CP9S1ou5Cod//QAfmguc5GUGEk7IfTUJ8VU9CvL6iOfI3qK6Rg7uVNWACTWKBqCWGQstBkEEkwLDZHzJBqoJ6CoE4vxyfEdowWLqt84fNhGcsgvVxqmEDIln0NA2gDRd/vhGi0yIh2JdMQ55+6Ten1+fVb+kwYlKxe94XyMV84Yiz+bfPkAach22oYCZyMx695JSBnaUb8MRLISlnkcpLv/UJtmEMlGER/t5Ac5BK00sbkbVo4zOMbfOgA++prt4mbpceTGyJpmkRa/75xoqDPbYxG3sYujq52RguW1YO649M=\">>}]}]}"
However, when I try to fetch this value in my API, only the following data is available:
{xmlel,<<\"encrypted\">>,\n [{<<\"xmlns\">>,<<\"eu.siacs.conversations.axolotl\">>}],\n [{xmlel,<<\"header\">>,\n [{<<\"sid\">>,<<\"344245169\">>}],\n [{xmlel,<<\"key\">>,\n [{<<\"rid\">>,<<\"684863397\">>}],\n [{xmlcdata,<<\"MwohBTL6tSWIPtugiO0qo0RNrWFC3ypIL5JpwMN1qF8jAoQ1EAAYASIwKnIw/zo43lF4At93Q7PMePlDVGF47Hf6xIvSjm+bpcESskndwFudirxigLSqc6J/P0IEL3sErsE
I am new to erlang and not sure of what seems to be the problem. Any help is appreciated.
I have a Dynamodb table with a few fields - my_id is the PrimaryKey. In the API gateway I set up a response with a method that takes in a parameter {my_id}.
Then I have an Integration Request mapping template that takes the passed in parameter and queries the table to return all the fields that match.
Then I have an Integration response mapping template that cleans up the returned items the way I want.
This all works perfect.
The thing I can't figure out how to do is if the parameter that is passed in doesn't match anything in the table, how do I get it to change from a 200 status into a 404?
From what I can tell when the passed in parameter doesn't match anything it doesn't cause an error, it just doesn't return anything.
It seems like I need to change the mapping template on the Integration response to first check if the params are empty and then somehow tell it to change the response status.
I can find info about this type of thing with people using Lambda, but I am not using Lambda - just the Dynamodb table and the API Gateway.
You can use Mapping Template to convert the response that you get from DDB and overrride the response code. You can get more details in the link https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-override-request-response-parameters.html
If you are using cloud formation, you can do this by using below snippet
IntegrationResponses:
- StatusCode: "200"
ResponseTemplates:
application/json: |
{
"payload" : {
}
},
}
IntegrationResponses:
- StatusCode: "200"
ResponseTemplates:
application/json: |
#set($inputRoot = $input.path('$'))
#if($inputRoot.toString().contains("Item"))
$input.json("$")
#set($context.responseOverride.status = 200)
#else
#set($context.responseOverride.status = 404)
#end
Api gateway currently supports mapping the status code using the status code of the integration response (Here dynamodb response code). The only workaround is to use a lambda function which outputs different error messages that can be mapped using a error regex http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-method-settings-execution-console.html.
I am attempting to return an object from a AWS Lambda function instead of a simple string.
// ...
context.fail({
"email": "Email address is too short",
"firstname": "First name is too short"
});
// ...
I have already used the errorMessage for mapping error responses to status codes and that has been great:
// ...
context.fail('That "username" has already been taken.');
// ...
Am I simply trying to do something that the AWS API Gateway does not afford?
I have also already found this article which helped: Is there a way to change the http status codes returned by Amazon API Gateway?.
Update
Since time of writing, lambda has updated the invocation signature and now passes event, context, callback.
Instead of calling context.done(err, res) you should use callback(err, res). Note that what was true for context.done still applies to the callback pattern.
Should also add that with API Gateways proxy and integration implementation this entire thread is pretty much obsolete.
I recommend reading this article if you are integrating API Gateway with Lambda: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html
Original response below
First things first, let's clear a few things up.
context.done() vs. context.fail()/context.success
context.done(error, result); is nothing but a wrapper around context.fail(error); and context.success(response);
The Lambda documentation clearly states that result is ignored if error is non null:
If the Lambda function was invoked using the RequestResponse (synchronous) invocation type, the method returns response body as follows:
If the error is null, set the response body to the string representation of result. This is similar to the context.succeed().
If the error is not null, set the response body to error.
If the function is called with a single argument of type error, the error value will be populated in the response body.
http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-context.html
What this means is that it won't matter whether you use a combination of fail/success or done, the behaviour is exactly the same.
API Gateway and Response Code Mapping
I have tested every thinkable combination of response handling from Lambda in combination with Response code mapping in API Gateway.
The conclusion of these tests are that the "Lambda Error RegExp" is only executed against a Lambda error, i.e: you have to call context.done(error);or context.fail(error); for the RegExp to actually trigger.
Now, this presents a problem as, has already been noted, Lambda takes your error and sticks it in an object and calls toString() on whatever you supplied:
{ errorMessage: yourError.toString() }
If you supplied an error object you'll get this:
{ errorMessage: "[object Object]" }
Not very helpful at all.
The only workaround I have found thus far is to call
context.fail(JSON.stringify(error));
and then in my client do:
var errorObject = JSON.parse(error.errorMessage);
It's not very elegant but it works.
As part of my error I have a property called "code". It could look something like this:
{
code: "BadRequest",
message: "Invalid argument: parameter name"
}
When I stringify this object I get:
"{\"code\":\"BadRequest\",\"message\":\"Invalid argument: parameter name\"}"
Lambda will stick this string in the errorMessage property of the response and I can now safely grep for .*"BadRequest".* in the API Gateway response mapping.
It's very much a hack that works around two somewhat strange quirks of Lambda and API Gateway:
Why does Lambda insist on wrapping the error instead of just giving
it back as is?
Why doesn't API Gateway allow us to grep in the
Lambda result, only the error?
I am on my way to open a support case with Amazon regarding these two rather odd behaviours.
You don't have to use context.fail, use success but send different statusCode and an errorMessage, here is an example of how i format my output:
try {
// Call the callable function with the defined array parameters
// All the function called here will be catched if they throw exceptions
result.data = callable_function.apply(this, params);
result.statusCode = 200;
result.operation = operation;
result.errorMessage = ""
} catch (e) {
result.data = [];
result.statusCode = 500;
result.errorMessage = e.toString();
result.method = method;
result.resource = resource;
}
// If everything went smooth, send back the result
// If context succeed is not called AWS Lambda will fire the function
// again because it is not successfully exited
context.succeed(result);
Use the consumer logic to handle different errors case logic, don't forget that you pay for the time your function is running...
You should replace the use of your context.fail with context.done and use context.fail only for very serious Lambda function failures since it doesn't allow more than one output parameter. Integration Response is able to match mapping template by performing regex on the first parameter passed to context.done this also maps HTTP status code to the response. You can't pass this response status code directly from Lambda since it's the role of API Gateway Integration Response to abstract the HTTP protocol.
See the following:
context.done('Not Found:', <some object you can use in the model>);
and the Integration Response panel this setting:
You can replicate similar approach for any kind of error. You should also create and map the error model to your response.
For those who tried everything put on this question and couldn't make this work (like me), check the thedevkit comment on this post (saved my day):
https://forums.aws.amazon.com/thread.jspa?threadID=192918
Reproducing it entirely below:
I've had issues with this myself, and I believe that the newline
characters are the culprit.
foo.* will match occurrences of "foo" followed by any characters
EXCEPT newline. Typically this is solved by adding the '/s' flag, i.e.
"foo.*/s", but the Lambda error regex doesn't seem to respect this.
As an alternative you can use something like: foo(.|\n)*