API Gateway Mapping Template for context.requestTime is Blank - amazon-web-services

I'm attempting to to have an API Gateway act as a proxy to DynamoDB and I'm currently testing with a simple POST call to append the $context.requestId and $context.requestTime to my table. I am getting the following error message:
{
"__type": "com.amazon.coral.validate#ValidationException",
"message": "One or more parameter values were invalid: An AttributeValue may not contain an empty string"
}
and what is sent is:
Mon Apr 15 19:10:24 UTC 2019 : Endpoint request body after transformations: {
"TableName": "BurgerOrders",
"Item": {
"OrderId": {
"S": "1f54a90b-5fb2-11e9-8b31-c9003bb71ec2"
},
"RequestTime": {
"S": ""
}
}
}
The mapping template within Integration Request that I have is:
{
"TableName": "BurgerOrders",
"Item": {
"OrderId": {
"S": "$context.requestId"
},
"RequestTime": {
"S": "$context.requestTime"
},
}
}
I've tried to change $context.requestTime to $context.requestTimeEpoch and I get the same error.

I know this was posted a while back, but according to an AWS dev:
"At this time, [$context.requestTime] is only available when the API has been deployed and API call was invoked to deployed stage."
Source: https://forums.aws.amazon.com/thread.jspa?messageID=697652

Related

Appsync as Proxy to another Graphql server

I have a existing graphql server provied by 3rd party. I also have my own backend running on EC2 to provide APIs.
I'm trying to build the appsync with aws-cdk for connecting to both 3rd party graphql and my backend instance also.
With the graphql server, appsync will act as proxy to forward queries only. My questions are:
Do we have anyway to load remote schema and populate it in appsync along with its schema?
How can we forward the requests to another graphql server using aws-cdk? I'm trying something like this:
private get _requestMappingTemplate(): string {
return `
{
"version": "2018-05-29",
"method": "GET",
"resourcePath": $util.toJson("/graphql"),
"params": {
"headers": {
"Authorization": "Bearer $ctx.request.headers.Authorization"
},
"body": {
"query": "$util.escapeJavaScript($ctx.info.getSelectionSetGraphQL())"
}
}
}`;
}
But from the aws doc, getSelectionSetGraphQL returns string representation of the selection set, formatted as GraphQL schema definition language (SDL). Although fragments aren't merged into the selection set
Is that possible to setup AppSync for forwarding request to another GraphQL servers? Any best practice to follow?
It's quite a bit more complicated. I'm still working on it, and the best I got so far is given below. It still drops query arguments, so has limited use.
#* TODO: Add some more interesting info to the operation name, e.g. a timestamp *#
#set($operationName = $context.info.parentTypeName)
#set($payloadBody = {
"query": "$util.str.toLower($context.info.parentTypeName) $operationName { $context.info.fieldName $context.info.selectionSetGraphQL }",
"operationName": $operationName,
"variables": $context.info.variables
})
{
"version" : "2018-05-29",
"operation": "Invoke",
"payload":{
"path": "/graphql",
"httpMethod": "POST",
"headers": $util.toJson($ctx.request.headers),
"requestContext": {
"authorizer": {
"claims": $context.identity.claims
}
},
"body": "$util.escapeJavaScript($util.toJson($payloadBody))",
"isBase64Encoded": false
},
}

AWS API Gateway Response Template Mapping json string cannot be converted

My Spring Cloud Function(v3.1.6) based AWS Lambda function (without Lambda proxy integration) returns a list of data via API Gateway in the following format:
{
"isBase64Encoded": false,
"headers": {
"id": "<some_id>",
"contentType": "application/json",
"timestamp": "1644307568294"
},
"body": "{\"resultList\":[{\"id\":\"1\",\"name\":\"item\",(...some other fields...)}]}",
"statusCode": 200
}
My problem here is I want to return response.body in a JSON (ofc I've also created a Model schema) :
{
"resultList": [
{
"id": "1", "name": "item ",(...some other fields...)
}
]
}
I've configured an application/json based Response Template Mapping to transform the response to the desired format:
$util.parseJson($input.json('$.body'))
which returned that I wanted (check the attached image):
But when I call it via Postman, I've got this:
{
"message": "Internal server error"
}
and in CloudWatch I can see this logs:
2022-02-08T08:56:00.688+01:00 (...) Endpoint response body before transformations: [Binary Data]
2022-02-08T08:56:00.694+01:00 (...) Execution failed due to configuration error: Unable to transform response
What can be the problem?

MPGS (mastercard): How to tokenize a transaction (how to create token)?

I'm trying to create token with MPGS.
I'm following this guide:
https://sample-sub.domain.mastercard.com/api/documentation/integrationGuidelines/supportedFeatures/pickAdditionalFunctionality/tokenization/tokenization.html?locale=en_US#x_tokenConfiguration
In the section "Token Operations" > "Tokenize", it says:
You can use this operation to create or update a token by storing
payment details against the token. ...
I'm posting this to help people who are frustrating like me with MPGS. I faced series of issues, and pulled my hair off many times. So here's the issues I faced and how to solve them (I'm stuck with issue #4).
Issue #1: Invalid credentials.
Fix: Make sure you're hitting the correct URL.
https://example-subdomain.mastercard.com/..
https://some.other-example.mastercard.com/..
https://MILLION-OTHER-POSSIBILITIES.mastercard.com/..
Even the documentation guide link have these same sub-domains, so make sure you're hitting the correct URL, and make sure you're following the correct documentation link.
Issue #2: Invalid parameters, or server asking for parameters although you've provided them.
Fix: If using Postman, make sure you set the parameters in "Body" > "raw" as JSON, like so:
{
"sourceOfFunds": {
"provided": {
"card": {
"expiry": {
"month": "05",
"year": "21"
},
"number": "5123456789012346"
}
},
"type": "CARD"
}
}
Issue #3: Authorization required
Fix: If using Postman, click on "Authorization", set "Type" it to Basic Auth, for "Username" set it to merchant.YOUR_MERCHANT_ID, for "Password" set it to YOUR_API_PASSWORD
Issue #4 (stuck here): Value '9999999999999999' is invalid. Card token must not be supplied
Method: PUT
URL: https://test-my.sample.gateway.mastercard.com/api/rest/version/46/merchant/MY_MERCHANT_ID/token/9999999999999999
Authorization: set correctly in Authorization tab
Body > raw:
{
"sourceOfFunds": {
"provided": {
"card": {
"expiry": {
"month": "05",
"year": "21"
},
"number": "5123456789012346"
}
},
"type": "CARD"
}
}
Response:
{
"error": {
"cause": "INVALID_REQUEST",
"explanation": "Value '9999999999999999' is invalid. Card token must not be supplied",
"field": "tokenid",
"validationType": "INVALID"
},
"result": "ERROR"
}
Q: Not sure what to do to tokenize the transaction..?! I'm stuck with issue #4.
Ok, finally figured it out. MPGS has 2 ways to create/update tokens:
Tokenization where YOU provide the token (notice: PUT method)
Tokenization where MPGS generate the token for you (notice: POST method)
They're very similar.
I got it working with the 2nd option.
Note: This is POST method !!
Method: POST
URL: https://SUBDOMAIN_YOU_SHOULD_BE_USING.mastercard.com/api/rest/version/50/merchant/YOUR_MERCHANT_ID/token
In postman, set Authorization (as described in the question, in issue #3).
Sample data to send (in postman, this should be in Body > raw):
{
"sourceOfFunds": {
"provided": {
"card": {
"expiry": {
"month": "05",
"year": "21"
},
"number": "5123456789012346"
}
},
"type": "CARD"
}
}
Sample response:
{
"repositoryId": "1000000000002",
"response": {
"gatewayCode": "BASIC_VERIFICATION_SUCCESSFUL"
},
"result": "SUCCESS",
"sourceOfFunds": {
"provided": {
"card": {
"brand": "MASTERCARD",
"expiry": "0521",
"fundingMethod": "CREDIT",
"issuer": "BANCO DEL PICHINCHA, C.A.",
"number": "512345xxxxxx2346",
"scheme": "MASTERCARD"
}
},
"type": "CARD"
},
"status": "VALID",
"token": "9717501974559694",
"usage": {
"lastUpdated": "2019-02-25T09:36:54.928Z",
"lastUpdatedBy": "1015",
"lastUsed": "2019-02-25T09:36:54.928Z"
},
"verificationStrategy": "BASIC"
}

how to configure body mapping template for AWS gateway API which take string as input

I'm using AWS API gateway to create a post rest API. The rest API will add data in the dynamoDB table "Metadata" which has four columns.
The input to the rest API is a string like "2 -164 4104 1.50", where each space-separated value belongs to the "Metadata" table columns value in sequence order.
I'm unable to figure out how I can configure the Body Mapping Templates which can parse the input string and map it to table column in sequence order.
The required output is shown in below image:
https://i.stack.imgur.com/d2fpF.png
I tried to split the string, splitting is fine. But I'm getting Response as
"__type": "com.amazon.coral.service#SerializationException"
My mapping is content-type: application/json:
#set($rawAPIData=$inout.path('$'))
#set($s=$rawAPIData.split(""))
"TableName": "Metadata",
"Item": {
"id": {
"S": "$s.get(0)"
},
"cap": {
"S": "$s.get(1)"
},
"counter": {
"S": "$s.get(2)"
},
"timer": {
"S": "$s.get(3)"
}
}
Output logs:
Endpoint request body after transformations:
"TableName": "Metadata",
"Item": {
"id": {
"S": "2"
},
"cap": {
"S": "-164"
},
"counter": {
"S": "4104"
},
"timer": {
"S": "1.50"
}
}
Endpoint response headers: {Server=Server, Connection=keep-alive, x-amzn-RequestId=J89RJ8GPC2D95GT0AP284PQSPBVV4KQNSO5AEMVJF66Q9ASUAAJG, x-amz-crc32=3948637019, Content-Length=60, Date=Sun, 26 Nov 2017 07:08:49 GMT, Content-Type=application/x-amz-json-1.0}
Method response body after transformations: {"__type":"com.amazon.coral.service#SerializationException"}
Seems the problem is with using application/json as content type and providing input as a string. How can I solve this use case?
Help is much appreciated.

Alexa Skill ARN - The remote endpoint could not be called, or the response it returned was invalid

I've created a simple Lambda function to call a webpage, this works fine when I test it from the functions page however when trying to create a skill to call this function I end up with a "The remote endpoint could not be called, or the response it returned was invalid." error.
Lambda Function
var http = require('http');
exports.handler = function(event, context) {
console.log('start request to ' + event.url)
http.get(event.url, function(res) {
console.log("Got response: " + res.statusCode);
context.succeed();
}).on('error', function(e) {
console.log("Got error: " + e.message);
context.done(null, 'FAILURE');
});
console.log('end request to ' + event.url);
}
The Test Event code looks like this:
{
"url": "http://mywebsite.co.uk"
}
and I've added a trigger for the "Alexa Skills Kit".
The ARN for this function is showing as:
arn:aws:lambda:us-east-1:052516835015:function:CustomFunction
Alexa Skill (Developer Portal)
I've then created a skill with a simple Intent:
{
"intents": [
{
"intent": "CustomFunction"
}
]
}
and created an Utterance as:
CustomFunction execute my custom function
In the Configuration section for my skill I have selected the "AWS Lambda ARN (Amazon Resource Name)" option and entered the ARN into the box for North America.
In the Test -> Service Simulator section, I've added "execute my custom function" as the Text and this changes the Lambda Request to show:
{
"session": {
"sessionId": "SessionId.a3e8aee0-acae-4de5-85df-XXXXXXXXX",
"application": {
"applicationId": "amzn1.ask.skill.XXXXXXXXX"
},
"attributes": {},
"user": {
"userId": "amzn1.ask.account.XXXXXXXXX"
},
"new": true
},
"request": {
"type": "IntentRequest",
"requestId": "EdwRequestId.445267bd-2b4a-45ef-8566-XXXXXXXXX",
"locale": "en-GB",
"timestamp": "2016-11-27T22:54:07Z",
"intent": {
"name": "RunWOL",
"slots": {}
}
},
"version": "1.0"
}
but when I run the test I get the following error:
The remote endpoint could not be called, or the response it returned was invalid.
Does anyone have any ideas on why the skill can't connect to the function?
Thanks
The Service Simulator built into the Amazon Alexa Developer Console has known issues. Try copying the JSON generated by the Simulator and pasting it into your lambda function's test event. To access lambda's test events first find the blue 'Test' button. Next to that button select the (Actions Drop down menu) -> (Configure Test Event) -> Paste the provided JSON into the code area -> (Save and Test). Lambda's built in testing features are much more reliable than Alexa's.
If this does not solve the problem lambda's testing event returns a complete stackTrace and error codes. It becomes much easier to trouble shoot when every error isn't "The remote endpoint could not be called, or the response it returned was invalid."
{
"session": {
"sessionId": "SessionId.a3e8aee0-acae-4de5-85df-XXXXXXXXX",
"application": {
"applicationId": "amzn1.ask.skill.XXXXXXXXX"
},
"attributes": {},
"user": {
"userId": "amzn1.ask.account.XXXXXXXXX"
},
"new": true
},
"request": {
"type": "IntentRequest",
"requestId": "EdwRequestId.445267bd-2b4a-45ef-8566-XXXXXXXXX",
"locale": "en-GB",
"timestamp": "2016-11-27T22:54:07Z",
"intent": {
"name": "RunWOL",
"slots": {}
}
},
"version": "1.0"
}
​While uploading .zip, do not compress the folder into .zip.
Instead, go into the folder, select package.json, index.js and node modules & then compress them and then upload the .zip.
This error message is very broad and may imply a lot of different issues. I was getting this error and in my case it was a timeout issue. How long does that website you are pinging taking to respond? The timeout doesn't seem to be properly documented, see my original question here: Troubleshooting Amazon's Alexa Skill Kit (ASK) Lambda interaction