Wrong SQS AWS message when I'm subscribed from a SNS Topic - amazon-web-services

I'm having problems with the next design:
When I'm receiving the message in my SQS Subscriber, the model of message it's wrong, example:
{
"Type" : "Notification",
"MessageId" : "7a6789f0-02f0-5ed3-8a11-deebcd08f145",
"TopicArn" : "arn:aws:sns:us-east-2:167186109795:name_sns_topic",
"Message" : "My JSON message",
"Timestamp" : "1987-04-23T17:17:44.897Z",
"SignatureVersion" : "1",
"Signature" : "string",
"SigningCertURL" : "url",
"UnsubscribeURL" : "url",
"MessageAttributes" : {
"X-Header1" : {"Type":"String","Value":"value1"},
"X-Header2" : {"Type":"String","Value":"value2"},
"X-Header3" : {"Type":"String","Value":"value3"},
"X-HeaderN" : {"Type":"String","Value":"value4"}
}
}
The common model when recieve message from SQS should be:
{
"Records": [
{
"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
"receiptHandle": "MessageReceiptHandle",
"body": "Hello from SQS!",
"attributes": {
"ApproximateReceiveCount": "1",
"SentTimestamp": "1523232000000",
"SenderId": "123456789012",
"ApproximateFirstReceiveTimestamp": "1523232000001"
},
"messageAttributes": {},
"md5OfBody": "7b270e59b47ff90a553787216d55d91d",
"eventSource": "aws:sqs",
"eventSourceARN": "arn:{partition}:sqs:{region}:123456789012:MyQueue",
"awsRegion": "{region}"
}
]
}
In my handler Java Lambda (example code) is throwing an exception because the estructure of de message received is not SQS Event:
public class MyHandler implements RequestHandler<SQSEvent, String> {
#Override
public String handleRequest(SQSEvent event, Context context) {
LambdaLogger logger = context.getLogger();
for (SQSEvent.SQSMessage msg : event.getRecords()) {
logger.log("SQS message body: " + msg.getBody());
logger.log("Get attributes: " + msg.getMessageAttributes().toString());
msg.getMessageAttributes()
.forEach(
(k, v) -> {
logger.log("key: " + k + "value: " + v.getStringValue());
});
}
return "Successful";
}
}
How can I do for handle the message thats its receiving ?

In my opinion this isn't documented too well but it's not bad once you figure it out.
The first thing is that I don't use the predefined Lambda objects. I read everything into a String and take it from there. So the base of my Lamda function is:
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
// copy InputStream to String, avoiding 3rd party libraries
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
String jsonString = result.toString();
}
When you "go direct" from SNS to Lambda the message looks something like (some fields removed for sake of length):
{
"Records": [
{
"EventSource": "aws:sns",
"EventVersion": "1.0",
"Sns": {
"Type": "Notification",
"Subject": "the message subject",
"Message": "{\"message\": \"this is the message\", \"value\": 100}",
"Timestamp": "2020-04-24T21:44:28.220Z",
"SignatureVersion": "1"
}
}
]
}
I had sent in a test message in JSON with two simple fields. Using JsonPath the "message" field inside of everything is read with:
String snsMessage = JsonPath.read(jsonString, "$.Records[0].Sns.Message");
String realMessage = JsonPath.read(snsMessage, "$.message");
But when it goes SNS -> SQS -> Lambda (or, indeed any SNS -> SQS path) the SNS message is now mostly wrapped and escaped in an SQS message:
{
"Records": [
{
"messageId": "ca8c53e5-8417-4479-a720-d4ecf970ca68",
"body": "{\n \"Type\" : \"Notification\",\n \"Subject\" : \"the message subject\",\n \"Message\" : \"{\\\"message\\\": \\\"this is the message\\\", \\\"value\\\": 100}\"\n}",
"attributes": {
"ApproximateReceiveCount": "1"
},
"md5OfBody": "6a4840230aca6a7bf7934bf191a529b8",
"eventSource": "aws:sqs"
}
]
}
So in this case, the value is in Records[0].body but that contains another JSON object. I'll admit that there is likely an easier way but from what I found I had to parse 3 times:
String sqsBody = <as read in lambda>;
String recordBody = JsonPath.read(sqsBody, "$.Records[0].body");
String internalMessage = JsonPath.read(recordBody, "$.Message");
// now read out of the sns message
String theSnsMessage = JsonPath.read(message, "$.message");

Related

How to read a json obj created with the nlohmann::json lib

I'm getting a JSON string from a curl request, like this:
[
{
"name": "P309",
"path": "P309",
"sha": "b9dbfa7ceb9db3b73c84ff326a418bdd50c1b227",
"type": "file",
"_links": {
"self": "https://api.github.com/repos//files/contents/P309?ref=main",
"git": "https://api.github.com/repos//files/git/blobs/b9dbfdd50c1b227",
"html": "https://github.com//files/blob/main/P309"
}
},
{
"name": "P310",
"path": "P310",
"sha": "b9dbfa7ceb9db3b73c84ff326a418bdd50c1b227",
"_links": {
"self": "https://api.github.com/repos//files/contents/P309?ref=main",
"git": "https://api.github.com/repos//files/git/blobs/b9dbfdd50c1b227",
"html": "https://github.com//files/blob/main/P309"
}
},
]
How can I parse/read it using the nlohmann::json lib?
I've found this example:
/*
"emulators": [
{
"general_info": {
"dev_id": "0123456789"
}
}
]
*/
for(json& o : data["emulators"]) {
json& gi = o["general_info"];
std::cout << gi["dev_id"] << '\n';
}
My JSON being parsed doesn't have any 'title/header', I'm confused about how to read it.
I tried:
using json = nlohmann::json;
json data = json::parse(downloaded_data);
for(json& o : data[0]) {
auto git = o["git"].get<std::string>();
auto name = o["name"].get<std::string>();
}
git outputs the value correctly, however, when reading name it throws an exception.
This is the value of data in the debugger
and this, of o.
Can I get any help on this?

databind.exc.MismatchedInputException: Cannot deserialize value - for micronaut - BFF test

I am working in micronaut graphQL and writing a test. The logic seems to be pretty straight forward. I am making a mock call and suppose to receive a fake response. The request been called without issues I can see it in the logs. But it seems like it is not able to parse the data and deserialize it. I am trying to make a test for a request but got deserialize error
Here is the error message
message -> Error code: GENERIC_ERROR, description: Exception getData, executionId: 770c8b9b-47cd-445e-9739-19ca0fd890c2, detailedInfo: message = Error instantiating bean of type [com.web.MyApi]: Cannot deserialize value of type `java.util.ArrayList<java.lang.String>` from Object value (token `JsonToken.START_OBJECT`)
at [Source: (String)"{
"data": {
"values": {
"formatted": [
{
"name": "2",
"lastName": "15"
}
]
}
}
}"; line: 5, column: 9] (through reference chain: com.web.DataResponse["data"]->com.web.Values["formatted"]->java.util.ArrayList[0]), cause = com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.ArrayList<java.lang.String>` from Object value (token `JsonToken.START_OBJECT`)
at [Source: (String)"{
"data": {
"metr
My test
given("my query description ") {
val scoreCardInfoRequestGraph =
"""
query{
getData(number:"6528")
{
name
lastName
}
}
""".toEscapedQuery()
`when`("posting the query") {
val dto =
client.getResponse(
myGraph,
ReportDataResponse::class.java
)
then("check the score card data formatted correctly") {
//verify
}
}
}
My graph for mocking the response
{
"data": {
"values": {
"formatted": [
{
"name": "2",
"lastName": "15"
}
]
}
}
}
And classes that I use for parsing
data class ReportDataResponse(
#JsonProperty("data")
val data: Data
)
data class Data(
#JsonProperty("values")
val values: Values
)
data class Values(
#JsonProperty("formatted")
val formatted: List<List<String>>
)

How to decrypt an encrypted payload in hyperledger?

I am currently using Hyperledger Fabric. I am using the REST API to make GET request as so:
curl 172.18.0.3:7050/chain/blocks/31
And the output I am getting back is :
{
"transactions": [
{
"type": 2,
"chaincodeID": "BMBQHHg2y0RnadYEaZZT8icjMvZbDPjkn5mFb+clFORxJqz8qsMs/QlalCT+A3msuc59KYM5sbZyhM3OeSplTWo91WAHTUgqIKVrm1gUzsouBIqLNvpqgimN36+s0ywF0Rx4gn27RmQYBbB+877Nh+w7A8Ezz92T1MgHcmzfRgVaDmiN0ga+jAfufNYglmeM4ZSysmSsz6xJtrcD5mTmHXZtvtw6uGCI1TCOMBaWTpLhNHfM2/5EB5jatdMjDi1GAlaXkDWcLgGjScL1yZpWcntz/N0cT90r6i9ycXZ0kk9wodBq2cFutDTdkl8S90kzd0gXig==",
"payload":"BBYZD6S/hRILcf21zVbhMAhA+qLQvAq+KvOBuXOknPCAMjas2LI9f42AKG6r+uWP71LYEkbo1XXANuDmukZjDsFGltzoIfq+Mry5n/CNXzXgiVLX0J7z08kGfEfw2vnywgmVFX4UtKPpl8pMTmRxJWn5Q0HY1pFnA6ZaXluoLRf7f17Ko4SPahi19k2NszcJ0SHE7xRllfLXZJxaOlT2J56nqjTBKTJ86bdqn6AdQXHA6Px7yz5XpgJhccyecaLS4sYcsrqHoOlO+kk+bw5Q6qnkHfIIhLXCEgHxKoT00L8I8B2luO1RlmQd4mNfXb7GrLOJXvCNPrcpSEmQDByEGwn1j3Zy0lilwKVaNYTPNThMwQ==",
"txid": "72bd2ab7-f769-49c9-a754-c7be0c481cf0",
"timestamp": {
"seconds": 1496062124,
"nanos": 474977395
},
"confidentialityLevel": 1,
"confidentialityProtocolVersion": "1.2",
"nonce": "2YgU+0WYPuTKGsKkT1hx7McOURPTIRgG",
"toValidators": "BJWJi5aSycSaJBaLIciUxlhZNyRsW6es2pO7ljUmqxP2SLzgUJtDtAeG8S5SMq+RQ9iX9m8+HIUocrD2J1MBTJaxPWcs/dYFNp1zi8k1ogbEuIQJDe/Gb0mbYVoBqGgFjofiE2lrZTO+RBVmUBQkAoybloOMUSfMawpOPTt/cIeNBq3M+t6gbTSl0ZVs5ofITWtonwhG8PNnlZwEmTLkC7evX1ImivMqo47ONxHXJlbbtjf+pL5kaqU5DrXWiv2L6Wt0xc11od4rbotnAQP2w2dqKTy2fj4ON6qCBp8i+t2FRi/iO0INJpI0aDjdkVCR",
"cert": "MIICUjCCAfigAwIBAgIRAJOBK8HG3E/Pmw8fZwL4iuswCgYIKoZIzj0EAwMwMTELMAkGA1UEBhMCVVMxFDASBgNVBAoTC0h5cGVybGVkZ2VyMQwwCgYDVQQDEwN0Y2EwHhcNMTcwNTI5MTEyNzQwWhcNMTcwODI3MTEyNzQwWjBFMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLSHlwZXJsZWRnZXIxIDAeBgNVBAMTF1RyYW5zYWN0aW9uIENlcnRpZmljYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6QVLJ48eCVlS1S8/BiSTU1XiWR0tZ6NGF3OZr306sTcgG/nYtcjx6/yJNwDgdYz5Boi7sA2QWUcqUkWfIPNWPKOB3DCB2TAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADANBgNVHQ4EBgQEAQIDBDAPBgNVHSMECDAGgAQBAgMEME0GBioDBAUGBwEB/wRArYyx9l4zJL4TbxDHuGZBsJ545Jsph/D/Q/FgMTTtxPh93B+LV6AI1tyFVHWiKNS4GgvDVlmgfwFuMAca+/PaujBKBgYqAwQFBggEQPEdAS1h/9LJJmqriV+42k0bL+ghGFbHa5GiEAitiMjlduiwgfelPK/rbAq0a6NrnPXCEYe1aWCSqyqsEfHGBoIwCgYIKoZIzj0EAwMDSAAwRQIhAOidYaESZ3xyZBTgcBOm3zyXvGb4YCCt7I7+M0gZF4xzAiAgYuCf7FPGx3fnJdABlZjszA1pR6jaPtIOQN2ndfAFZA==",
"signature": "MEUCIQCVBtfjk3yzwfOFyOojH5tynq3HrG7dFN9URXB5C6kYDAIgLPcwJBAIVlD1I4dxzczfxmywlZn1ZMSvL2djioWgqFQ="
}
],
"stateHash": "9KEsiBp4t/VZyETXMASSYtuPuf8JowktCSbX7daPt69uqDzrJvifrPIXpI5N1kOayoq6H0afM8zN/WZpWsesHQ==",
"previousBlockHash": "v6Fo6SARD0xdE0B/jvIq22kgV5uLAKhTwLjrA4YRBskWcZOjECFbNgzlwFQhEmbar1zcAbcZVo9eo/3tx2y68g==",
"consensusMetadata": "CCA=",
"nonHashData": {
"localLedgerCommitTimestamp": {
"seconds": 1496062125,
"nanos": 496018341
},
"chaincodeEvents": [
{
},
{
}
]
}
}
So I had performed a invoke to
transfer 10 from a to b.
And i got this payload.
The payload is encrypted as the
CORE_SECURITY_ENABLED=true and
CORE_SECURITY_PRIVACY=true
I know we have to use the certificate to decrypt the payload and then might be use base64 decoding to get the exact payload back.
But my question is what are the exact function calls or exact steps involved in doing so ?

Alexa conversational skill Error

I'm creating a skill in Alexa that does the following.
User : Hi
Alexa, hello please give me your name
User : John
Alexa : Hi John, good to meet you. How old are you
User : 25
Below are my intents
{
"intents": [
{
"intent": "StartTheFlow",
"slots": [
{
"name": "custName",
"type": "list_of_userNames"
},
{
"name": "age",
"type": "AMAZON.NUMBER"
}
]
},
{
"intent": "AMAZON.HelpIntent"
},{
"intent": "Welcome"
},
{
"intent": "AMAZON.StopIntent"
},
{
"intent": "AMAZON.CancelIntent"
}
]
}
And below are my utterances
StartTheFlow Hi
StartTheFlow {custName}
StartTheFlow {age}
Below is my onIntent()
#Override
public SpeechletResponse onIntent(final IntentRequest request, final Session session) throws SpeechletException {
log.info("onIntent requestId={}, sessionId={}", request.getRequestId(), session.getSessionId());
Intent intent = request.getIntent();
String intentName = (intent != null) ? intent.getName() : null;
if ("StartTheFlow".equals(intentName)) {
return getTheFlow(intent, session);
} else if ("AMAZON.HelpIntent".equals(intentName)) {
return getHelpResponse();
} else if ("WelcomeChubb".equals(intentName)) {
return getWelcomeResponse();
} else {
throw new SpeechletException("Invalid Intent");
}
}
And I'm trying to handle this as below
private SpeechletResponse getTheFlow(Intent intent, Session session) {
boolean isAskResponse = true;
String responseText = "";
String nameFromSession = (String) session.getAttribute("name");
if (StringUtils.isNullOrEmpty(nameFromSession)) {
responseText = "please give me your name";
getTheNameText(intent, session);
} else {
System.out.println(session.getAttribute("nameFromSession"));
responseText = "please give me your date of birth";
}
return getSpeechletResponse(responseText, "", isAskResponse);
}
private String getTheNameText(Intent intent, Session session) {
String userNameFrmIntent = getNameFromSlot(intent).toString();
session.setAttribute("nameFromSession", userNameFrmIntent);
return getNameFromSlot(intent).toString();
}
private String getNameFromSlot(Intent intent) {
Slot userName = intent.getSlot(Slot_Name);
return userName.getValue();
}
Also, I've defined a slot in the top as below.
private static final String Slot_Name = "custName";
But here when I type Hi, Instead of asking me my name, it is giving me an error in logs it shows Java NullPointer Exception. the response that I get when I type Hi is as below.
{
"session": {
"sessionId": "SessionId.a2740ca4-73ff-4a15-856d-6461b3c7b2e1",
"application": {
"applicationId": "amzn1.ask.skill.e3dfb30e-0089-423c-a325-30ad28dd2e2b"
},
"attributes": {},
"user": {
"userId": "amzn1.ask.account.AEQYTT5HFHEGGDSUCT3NW45HKR7O3FBL5YCBSZIS7P5LNP5BXFEMUR7AUYOZVKC2FT5V6RKJC7RNA5VMZVREBAXAQP3NFNTQSFSSKSEXIYT4FQYMS5JCI2CCAOPUF4FN4C6DHEU6ONNY3D6GN5AWK75KOQNJH2IWROIIXTPNXSNI6FLQYRBBMP7TRSOWVNCY73WJUT2VLHDACWA"
},
"new": true
},
"request": {
"type": "IntentRequest",
"requestId": "EdwRequestId.cf686fc0-cbfd-4496-bb09-c41714563507",
"locale": "en-US",
"timestamp": "2017-02-15T20:12:44Z",
"intent": {
"name": "StartTheFlow",
"slots": {
"custName": {
"name": "custName",
"value": "hi"
}
}
}
},
"version": "1.0"
}
Can someone please let me know where am I going wrong and how can I fix this, I've quite a number of questions to be linked, like 25, can Someone please let me know if there is a better way to do this in java.
Thanks
I would recommend creating a separate intent for each thing that the user says. So for example, HelloIntent, NameIntent, and AgeIntent.
Then be sure to pass those bits of information forward to all following intents in the session. So each intent could use a common function at the beginning to read each string from the session (if exists), add the new slot data to it, and then write all the strings back to the response session before finishing.
Since you'll then have separate intents, and the user could conceivably say them out of order, you may want to check that all the needed strings have been entered, or else prompt the user for any missing strings.
The problem with saving data in the session is that the data will be gone the next time the user starts the skill. To resolve this, you could use a database to hold the users data, saving it keyed to the userId. There are lots of examples on how to do that. Be careful that some databases are essentially free, but others will charge you depending on how many times it is used each month.

How to get entire request headers/querystrings in Serverless framework?

I started to try Serverless framework, but it looks little confusable for some points...
One of them is request headers/querystrings,
I made request template like this:
s-templates.json
{
"apiRequestTemplate": {
"application/json": {
"httpMethod": "$context.httpMethod",
"body": "$input.json('$')",
"queryParams" : "$input.params().querystring",
"headerParams" : "$input.params().header",
"headerParamNames" : "$input.params().header.keySet()",
"contentTypeValue" : "$input.params().header.get('Content-Type')"
}
}
}
s-function.json
"requestParameters": {},
"requestTemplates": "$${apiRequestTemplate}",
With this setting, I expected to get the request something like this:
{
"body" : {}
"contentTypeValue" : ""
"headerParamNames" : ["Accept", "Accept-Encoding", ... ],
"headerParams" : {
"Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding" : "gzip, deflate, sdch, br, Accept-Language=ja,en-US;q=0.8,en;q=0.6",
...
},
"httpMethod" : "GET",
"queryParams" : {
"category" : "Some Category"
}
}
But in real, what I get is:
{
"body" : {}
"contentTypeValue" : ""
"headerParamNames" : "[Accept,Accept-Encoding, ... ]",
"headerParams" : "{Accept=text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", Accept-Encoding=gzip, deflate, sdch, br, Accept-Language=ja,en-US;q=0.8,en;q=0.6", ...}",
"httpMethod" : "GET",
"queryParams" : "{category=Some Category}"
}
This results inconvenient to handle.
I know also, method like below:
s-function.json
"requestParameters": {},
"requestTemplates": {
"application/json": "{\"category\":\"$input.params('category')\"}"
},
But this is also inconvenient need to specify all parameters in configuration..
Is there any way to get entire request-headers / query-strings as json object in lambda function?
Modified after answer
I tried to change s-template.json to
"queryParams" : "$util.parseJson($input.params().querystring)",
"headerParams" : "$util.parseJson($input.params().header)",
But result was same...
And, in AWS document, what I want can be seen here: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#input-variable-reference
#set($allParams = $input.params())
{
"params" : {
#foreach($type in $allParams.keySet())
#set($params = $allParams.get($type))
"$type" : {
#foreach($paramName in $params.keySet())
"$paramName" : "$util.escapeJavaScript($params.get($paramName))"
#if($foreach.hasNext),#end
#end
}
#if($foreach.hasNext),#end
#end
}
}
But I don't know how to set this setting to Serverless framework's s-templates.json...
I use following request template. It will wrap data, path, headers,params,query into a JSON object and pass it to the function.
{
"application/json": {
"data": "$input.json('$')",
"path": "$context.resourcePath",
"method": "$context.httpMethod",
"headers": "{#foreach($header in $input.params().header.keySet())\"$header\": \"$util.escapeJavaScript($input.params().header.get($header))\" #if($foreach.hasNext),#end#end}",
"params": "{#foreach($param in $input.params().path.keySet())\"$param\": \"$util.escapeJavaScript($input.params().path.get($param))\" #if($foreach.hasNext),#end#end}",
"query": "{#foreach($queryParam in $input.params().querystring.keySet())\"$queryParam\": \"$util.escapeJavaScript($input.params().querystring.get($queryParam))\" #if($foreach.hasNext),#end#end}"
}
}
You can refer Apache Velocity Templates to get better understanding about the inner syntax such as #foreach($header in .....).
Have you tried $util.parseJson()? It takes the json as a string and turns it into a traditional json object.