Alexa Skill: Playing Audio results in "Sorry don't know that" - json

I am coding my very first alexa skill and am very excited! I am trying to make a skill so that when I say "ramranch", alexa will play Sunil Syal. I started this skill using the space fact picker blueprint. I have deleted that code and put in my own. The aws is connected and is working, however when I say "ramranch" in the testing console, Alexa responds with "Sorry, I don't know that". Their is no debug or error message.
/* eslint-disable func-names */
/* eslint-disable no-console */
const Alexa = require('ask-sdk');
const RamRanch = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest'
|| (request.type === 'IntentRequest'
&& request.intent.name === 'handle');
},
handle(handlerInput) {
this.emit(':tell', "Let's enjoy a world's most beautiful composition, composed by the great, Sunil Syal, <audio src='https://my-apis.000webhostapp.com/audio/Romantic%20Solitude-Instrumental%20(Flute).mp3'/> Wow, That is amazing. Click the link on top right corner to listen to full song.");
}
}
const HelpHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& request.intent.name === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak(HELP_MESSAGE)
.reprompt(HELP_REPROMPT)
.getResponse();
},
};
const ExitHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& (request.intent.name === 'AMAZON.CancelIntent'
|| request.intent.name === 'AMAZON.StopIntent');

There is a strong likelihood that when you modified the blueprint skill you may have deleted the node modules. Here is a slightly modified version of your index.js code. Begin a node project npm init. next npm install ask-sdk. your project folder will now have node_modules, package-lock.json, and package.json add this index.js file.
const Alexa = require('ask-sdk-core');
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
const speechText = 'Welcome to the Alexa Skills Kit, you can say what about ramranch';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('Ramranch', speechText)
.getResponse();
}
};
const RamranchIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'ramranchIntent';
},
handle(handlerInput) {
const speechText = 'Lets enjoy a worlds most beautiful composition, composed by the great, Sunil Syal, <audio src="https://my-apis.000webhostapp.com/audio/Romantic%20Solitude-Instrumental%20(Flute).mp3"/> Wow, That is amazing. Click the link on top right corner to listen to full song.';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('Ramranch', speechText)
.getResponse();
}
};
const HelpIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
const speechText = 'You can say what about Ramranch!';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('Ramranch', speechText)
.getResponse();
}
};
const CancelAndStopIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent'
|| handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent');
},
handle(handlerInput) {
const speechText = 'Goodbye!';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('Ramranch', speechText)
.getResponse();
}
};
const SessionEndedRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
},
handle(handlerInput) {
//any cleanup logic goes here
return handlerInput.responseBuilder.getResponse();
}
};
const ErrorHandler = {
canHandle() {
return true;
},
handle(handlerInput, error) {
console.log(`Error handled: ${error.message}`);
return handlerInput.responseBuilder
.speak('Sorry, I can\'t understand the command. Please say again.')
.reprompt('Sorry, I can\'t understand the command. Please say again.')
.getResponse();
},
};
exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
RamranchIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler)
.addErrorHandlers(ErrorHandler)
.lambda();
Be sure to modify your Alexa skill developer model to include a ramranchIntent as I have not combined launch and primary intents as in your code. Lastly, zip this with the other previously mentioned files into your lambda function in AWS and add some intent phrases for triggering Ramranch, in my tests I used this skill JSON
{
"interactionModel": {
"languageModel": {
"invocationName": "ramranch player",
"intents": [
{
"name": "AMAZON.FallbackIntent",
"samples": []
},
{
"name": "AMAZON.CancelIntent",
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": []
},
{
"name": "AMAZON.StopIntent",
"samples": []
},
{
"name": "AMAZON.NavigateHomeIntent",
"samples": []
},
{
"name": "ramranchIntent",
"slots": [],
"samples": [
"what about ramranch",
"lets hear ramranch"
]
}
],
"types": []
}
}
}

Related

Console.log json specific value

I'm working with some script and I would like to ask how to display on the console a specific json value.
For example, I have script:
Promise.all([
fetch('https://blockchain.info/balance?active=3C6WPNa5zNQjYi2RfRmt9WUVux7V4xbDmo').then(resp => resp.json()),
fetch('https://api.binance.com/api/v3/avgPrice?symbol=BTCEUR').then(resp => resp.json()),
]).then(console.log)
output:
[{
3C6WPNa5zNQjYi2RfRmt9WUVux7V4xbDmo: {
final_balance: 185653,
n_tx: 1,
total_received: 185653
}
}, {
mins: 5,
price: "19230.49330261"
}]
I want to console price and final_balance.
Best regards!
One way you could achieve this is by flattening the array and objects within because there's no predefined structure of what the output looks like.
Here, I'm assuming the output you mentioned is always an array of objects.
const flattenObject = (obj = {}) =>
Object.keys(obj || {}).reduce((acc, cur) => {
if (typeof obj[cur] === "object") {
acc = { ...acc, ...flattenObject(obj[cur]) };
} else {
acc[cur] = obj[cur];
}
return acc;
}, {});
const outputs = [
{
"3C6WPNa5zNQjYi2RfRmt9WUVux7V4xbDmo": {
final_balance: 185653,
n_tx: 1,
total_received: 185653,
},
},
{
mins: 5,
price: "19230.49330261",
},
];
outputs.forEach((output) => {
const flatOutput = flattenObject(output);
console.log("flatOutput:", flatOutput);
if (flatOutput.final_balance) {
console.log("final_balance:", flatOutput.final_balance);
}
if (flatOutput.price) {
console.log("price:", flatOutput.price);
}
});

How to pass object or json stringify to custom function in office js?

I am working on an office js add-in now I have created a custom function that works as expected but when I pass JSON stringify string in the custom function it does not work and does not give any error. if I have to pass a simple comment then it working correctly. I follow this solution but had no luck https://learn.microsoft.com/en-us/office/dev/add-ins/excel/custom-functions-parameter-options?tabs=javascript. here is my code Please guide me on what I do wrong. Thank in advanced
await Excel.run(async (context) => {
const wb = context.workbook;
const range = wb.getSelectedRange();
const abc={id:1,name:"KC"}
serialzedFieldMappings=JSON.stringify(abc)
try {
range.formulas = [[`=ANALYST.LOG(${serialzedFieldMappings})`]];
} catch (error) {
console.log(error);
}
return context.sync();
});
function.json file
{
"functions": [
{
"description": "Writes a message to console.log().",
"id": "LOG",
"name": "LOG",
"parameters": [
{
"description": "String to write.",
"name": "message",
"type": "string"
}
],
"result": {}
}
]
}
function.js
function logMessage(message) {
console.log("message", message);
return `Cmarix Example${message}`;
}
CustomFunctions.associate("LOG", logMessage);
Please follow below solution for your problem
await Excel.run(async (context) => {
console.log("data");
const wb = context.workbook;
const range = wb.getSelectedRange();
const timeDimension: any = selectedTimeDimensions[0];
const dimension: any = selectedDimensions[0];
//Create jsonstringfy
const serialzedFieldMappings = new CellDimensionMapSerializer().Serialize(
selectedScenario,
[timeDimension],
[dimension]
);
const abc = { id: 1, name: "KC" }
let datastring = JSON.stringify(abc).split('"').join("'");
try {
range.formulas = [[`=ANALYST.COMMENT("${datastring}")`]];
} catch (error) {
console.log(error);
}
return context.sync();
});
If you want to let Excel treat a double quote as literal text in a formula, you need to escape it. Try the following code to see if it can help:
await Excel.run(async (context) => {
const wb = context.workbook;
const range = wb.getSelectedRange();
const abc = { id: 1, name: "KC" }
// An additional double quote will escape a double quote.
let serialzedFieldMappings = JSON.stringify(abc).replace(/"/g, `""`)
try {
range.formulas = [[`=("${serialzedFieldMappings}")`]];
} catch (error) {
console.log(error);
}
return context.sync();
});
Thanks!
Rundong

native messaging host chrome-token-signing

I am trying to make an extension that will communicate with a native messaging host chrome-token-signing (https://github.com/open-eid/chrome-token-signing).
I have installed extension , but the EXE is not started. I have message log TEST: {"message":"Invalid argument","result":"invalid_argument"}
Do I need to do Something
I have installed the host in the registry like
HKEY_LOCAL_MACHINE\software\Google\Chrome\NativeMessagingHosts\ee.ria.esteid
and value C:\Users\dev\Desktop\chrome-token-signing\host-windows\ee.ria.esteid.json
The native application manifest.json:
{
"name": "ee.ria.esteid",
"description": "Give signatures with your eID on the web",
"path": "chrome-token-signing.exe",
"type": "stdio",
"allowed_origins": [
"chrome-extension://ckjefchnfjhjfedoccjbhjpbncimppeg/"
]
}
manifest.json of extension
{
"name": "Token signing",
"version": "0.0.24",
"minimum_chrome_version": "40.0",
"manifest_version": 2,
"description": "Use your eID smart card on the web",
"icons": {
"48": "icon48.png",
"128": "icon128.png"
},
"content_scripts": [{
"matches": ["*://*/*", "file:///*"],
"exclude_matches": ["*://www.overdrive.com/*"],
"js": ["content.js"],
"run_at": "document_end",
"all_frames": true
}],
"background": {
"scripts": ["background.js"]
},
"permissions": ["nativeMessaging"],
"applications": {
"gecko": {
"id": "{443830f0-1fff-4f9a-aa1e-444bafbc7319}"
}
}
}
background.js
var NO_NATIVE_URL = "https://open-eid.github.io/chrome-token-signing/missing.html";
var HELLO_URL = "https://open-eid.github.io/chrome-token-signing/hello.html";
var DEVELOPER_URL = "https://github.com/open-eid/chrome-token- signing/wiki/DeveloperTips";
var NATIVE_HOST = "ee.ria.esteid";
var K_SRC = "src";
var K_ORIGIN = "origin";
var K_NONCE = "nonce";
var K_RESULT = "result";
var K_TAB = "tab";
var K_EXTENSION = "extension";
// Stores the longrunning ports per tab
// Used to route all request from a tab to the same host instance
var ports = {};
// Probed to false if host component is OK.
var missing = true;
console.log("Background page activated");
// XXX: probe test, because connectNative() does not allow to check the presence
// of native component for some reason
typeof chrome.runtime.onStartup !== 'undefined' && chrome.runtime.onStartup.addListener(function() {
// Also probed for in onInstalled()
_testNativeComponent().then(function(result) {
if (result === "ok") {
missing = false;
}
});
});
// Force kill of native process
// Becasue Port.disconnect() does not work
function _killPort(tab) {
if (tab in ports) {
console.log("KILL " + tab);
// Force killing with an empty message
ports[tab].postMessage({});
}
}
// Check if native implementation is OK resolves with "ok", "missing" or "forbidden"
function _testNativeComponent() {
return new Promise(function(resolve, reject) {
chrome.runtime.sendNativeMessage(NATIVE_HOST, {}, function(response) {
if (!response) {
console.log("TEST: ERROR " + JSON.stringify(chrome.runtime.lastError));
// Try to be smart and do some string matching
var permissions = "Access to the specified native messaging host is forbidden.";
var missing = "Specified native messaging host not found.";
if (chrome.runtime.lastError.message === permissions) {
resolve("forbidden")
} else if (chrome.runtime.lastError.message === missing) {
resolve("missing");
} else {
resolve("missing");
}
} else {
console.log("TEST: " + JSON.stringify(response));
if (response["result"] === "invalid_argument") {
resolve("ok");
} else {
resolve("missing"); // TODO: something better here
}
}
});
});
}
// When extension is installed, check for native component or direct to helping page
typeof chrome.runtime.onInstalled !== 'undefined' && chrome.runtime.onInstalled.addListener(function(details) {
if (details.reason === "install" || details.reason === "update") {
_testNativeComponent().then(function(result) {
var url = null;
if (result === "ok" && details.reason === "install") {
// Also set the flag, onStartup() shall be called only
// on next startup
missing = false;
// TODO: Add back HELLO page on install
// once there is a nice tutorial
url = HELLO_URL;
} else if (result === "forbidden") {
url = DEVELOPER_URL;
} else if (result === "missing"){
url = NO_NATIVE_URL;
}
if (url) {
chrome.tabs.create({'url': url + "?" + details.reason});
}
});
}
});
// When message is received from page send it to native
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if(sender.id !== chrome.runtime.id && sender.extensionId !== chrome.runtime.id) {
console.log('WARNING: Ignoring message not from our extension');
// Not our extension, do nothing
return;
}
if (sender.tab) {
// Check if page is DONE and close the native component without doing anything else
if (request["type"] === "DONE") {
console.log("DONE " + sender.tab.id);
if (sender.tab.id in ports) {
// FIXME: would want to use Port.disconnect() here
_killPort(sender.tab.id);
}
} else {
request[K_TAB] = sender.tab.id;
if (missing) {
_testNativeComponent().then(function(result) {
if (result === "ok") {
missing = false;
_forward(request);
} else {
return _fail_with (request, "no_implementation");
}
});
} else {
// TODO: Check if the URL is in allowed list or not
// Either way forward to native currently
_forward(request);
}
}
}
});
// Send the message back to the originating tab
function _reply(tab, msg) {
msg[K_SRC] = "background.js";
msg[K_EXTENSION] = chrome.runtime.getManifest().version;
chrome.tabs.sendMessage(tab, msg);
}
// Fail an incoming message if the underlying implementation is not
// present
function _fail_with(msg, result) {
var resp = {};
resp[K_NONCE] = msg[K_NONCE];
resp[K_RESULT] = result;
_reply(msg[K_TAB], resp);
}
// Forward a message to the native component
function _forward(message) {
var tabid = message[K_TAB];
console.log("SEND " + tabid + ": " + JSON.stringify(message));
// Open a port if necessary
if(!ports[tabid]) {
// For some reason there does not seem to be a way to detect missing components from longrunning ports
// So we probe before opening a new port.
console.log("OPEN " + tabid + ": " + NATIVE_HOST);
// create a new port
var port = chrome.runtime.connectNative(NATIVE_HOST);
// XXX: does not indicate anything for some reason.
if (!port) {
console.log("OPEN ERROR: " + JSON.stringify(chrome.runtime.lastError));
}
port.onMessage.addListener(function(response) {
if (response) {
console.log("RECV "+tabid+": " + JSON.stringify(response));
_reply(tabid, response);
} else {
console.log("ERROR "+tabid+": " + JSON.stringify(chrome.runtime.lastError));
_fail_with(message, "technical_error");
}
});
port.onDisconnect.addListener(function() {
console.log("QUIT " + tabid);
delete ports[tabid];
// TODO: reject all pending promises for tab, if any
});
ports[tabid] = port;
ports[tabid].postMessage(message);
} else {
// Port already open
ports[tabid].postMessage(message);
}
}
The native app is started and it replies to you that the arguments you give it are invalid.
You need to check with native app documentation and see what arguments are valid for that particular app and use them in the messages you send it from the extension. Your request will look like:
chrome.runtime.sendNativeMessage(NATIVE_HOST, {text: "some_valid_argument"}, function(response){
........

Determine DRM system supported by browser

I've trying to find out how to determine which DRM system browser is using. And in fact, only chrome say it is use 'com.widevine.alpha' where IE & Safari (Win) throw error on 'requestMediaKeySystemAccess', and firefox do not even try to say it use 'com.adobe.acccess' =]
function isKeySystemSupported(keySystem) {
var dfd = Q.defer();
console.log('check: ', keySystem);
navigator.requestMediaKeySystemAccess(keySystem, [{contentType: 'video/webm; codecs="vp9"'}]).then(function() {
dfd.resolve(true);
}, function() { dfd.resolve(false); } );
return dfd.promise;
}
is there any solution, like Modernizr or similar to get which keySystem I should use?
There are several websites offering such a check, like dash-player.com/browser-capabilities/ After having a closer look at how it is done, one can use something similar to:
// EME Check
var keySystems = {
widevine: ['com.widevine.alpha'],
playready: ['com.microsoft.playready', 'com.youtube.playready'],
clearkey: ['webkit-org.w3.clearkey', 'org.w3.clearkey'],
primetime: ['com.adobe.primetime', 'com.adobe.access'],
fairplay: ['com.apple.fairplay']
};
var keySystemsCount = (function () {
var count = 0;
for (keysys in keySystems) {
if (keySystems.hasOwnProperty(keysys)) {
count += keySystems[keysys].length;
}
}
return count;
})();
var testVideoElement = document.createElement('video');
var supportedSystems = [];
var unsupportedSystems = [];
var supportsEncryptedMediaExtension = function () {
if (!testVideoElement.mediaKeys) {
if (window.navigator.requestMediaKeySystemAccess) {
if (typeof window.navigator.requestMediaKeySystemAccess === 'function') {
console.log('found default EME');
hasEME = true;
var isKeySystemSupported = function (keySystem) {
var config = [{initDataTypes: ['cenc']}];
if (window.navigator.requestMediaKeySystemAccess) {
window.navigator.requestMediaKeySystemAccess(keySystem, config).then(function (keySystemAccess) {
supportedSystems.push(keySystem);
}).catch(function () {
unsupportedSystems.push(keySystem);
});
}
};
var keysys, dummy, i;
for (keysys in keySystems) {
if (keySystems.hasOwnProperty(keysys)) {
for (dummy in keySystems[keysys]) {
isKeySystemSupported(keySystems[keysys][dummy]);
}
}
}
}
} else if (window.MSMediaKeys) {
if (typeof window.MSMediaKeys === 'function') {
console.log('found MS-EME');
hasEME = true;
var keysys, dummy, i;
for (keysys in keySystems) {
if (keySystems.hasOwnProperty(keysys)) {
for (dummy in keySystems[keysys]) {
if (MSMediaKeys.isTypeSupported(keySystems[keysys][dummy])) {
supportedSystems.push(keySystems[keysys][dummy]);
} else {
unsupportedSystems.push(keySystems[keysys][dummy]);
}
}
}
}
}
} else if (testVideoElement.webkitGenerateKeyRequest) {
if (typeof testVideoElement.webkitGenerateKeyRequest === 'function') {
console.log('found WebKit EME');
hasEME = true;
var keysys, dummy, i;
for (keysys in keySystems) {
if (keySystems.hasOwnProperty(keysys)) {
for (dummy in keySystems[keysys]) {
if (testVideoElement.canPlayType('video/mp4', keySystems[keysys][dummy])) {
supportedSystems.push(keySystems[keysys][dummy]);
} else {
unsupportedSystems.push(keySystems[keysys][dummy]);
}
}
}
}
}
} else {
console.log('no supported EME implementation found');
hasEME = false;
}
}
}
Simply run supportsEncryptedMediaExtension() and supportedSystems will be filled with the desired information.
Note that the config object should be extended to include the specific codec claims respective to your particular media. It isn't enough to just detect the key system as codec support sometimes depends on Guest OS dependencies.
var config = [{
"initDataTypes": ["cenc"],
"audioCapabilities": [{
"contentType": "audio/mp4;codecs=\"mp4a.40.2\""
}],
"videoCapabilities": [{
"contentType": "video/mp4;codecs=\"avc1.42E01E\""
}]
}];
In addition to the information listed here, I want to mention that in Chrome, whether you are using https or not will affect the availability of navigator.requestMediaKeySystemAccess function.
In your development environment that probably is running on http, navigator.requestMediaKeySystemAccess will return undefined for Chrome whereas the same code will return a function in Firefox.
In your prod environment that has https, navigator.requestMediaKeySystemAccess will return a function both in Chrome and Firefox.
I had to give videoCapabilities flags to make this work.
function testEME() {
// https://shaka-player-demo.appspot.com/support.html
var keySysConfig = [{
"initDataTypes": ["cenc"]
//,"persistentState": "required" // don't use or MacSafari "not supported"
//,"persistentState": "required", "distinctiveIdentifier": "required"
//,"audioCapabilities": [{
// "contentType": "audio/mp4;codecs=\"mp4a.40.2\""
//}]
,"videoCapabilities": [{
"contentType": "video/mp4;codecs=\"avc1.4D401E\"" // avc1.42E01E = ConstrainedLevel3, 4D401E=MainLevel3
//,"robustness": "3000"
}]
}];
var keySystems = {
playready: ['com.microsoft.playready.recommendation', 'com.microsoft.playready'
, 'com.microsoft.playready.hardware', 'com.youtube.playready'],
clearkey: ['webkit-org.w3.clearkey', 'org.w3.clearkey'],
widevine: ['com.widevine.alpha'],
primetime: ['com.adobe.primetime', 'com.adobe.access'],
fairplay: ['com.apple.fairplay','com.apple.fps'
, 'com.apple.fps.1_0', 'com.apple.fps.2_0', 'com.apple.fps.3_0']
};
for(keyArr in keySystems) {
for(forItemIdx in keySystems[keyArr]) {
let keySys = keySystems[keyArr][forItemIdx];
try {
navigator.requestMediaKeySystemAccess(keySys, keySysConfig).
then(function(mediaKeySystemAccess) {
//let mkConfig = mediaKeySystemAccess.getConfiguration();
//let sFlags = "persistentState="+mkConfig.persistentState
// + ", distinctiveIdentifier="+mkConfig.distinctiveIdentifier;
console.log(keySys + " supported"); //+" ("+sFlags+")");
}).catch(function(ex) {
console.log(keySys+" not supported (" + ex.name+" "+ex.message+")." );
});
} catch (ex) {
console.log(keySys+" not supported (" + ex.name+" "+ex.message+").." );
}
}
}
}

Formatting DynamoDB data to normal JSON in AWS Lambda

I'm using AWS Lambda to scan data from a DynamoDB table. This is what I get in return:
{
"videos": [
{
"file": {
"S": "file1.mp4"
},
"id": {
"S": "1"
},
"canvas": {
"S": "This is Canvas1"
}
},
{
"file": {
"S": "main.mp4"
},
"id": {
"S": "0"
},
"canvas": {
"S": "this is a canvas"
}
}
]
}
My front-end application is using Ember Data Rest Adapter which does not accepts such response. Is there any way I can get normal JSON format? There is this NPM module called dynamodb-marshaler to convert DynamoDB data to normal JSON. I'm looking for a native solution if possible.
Node.js
Use the unmarshall function from AWSJavaScriptSDK:
const AWS = require("aws-sdk");
exports.handler = function( event, context, callback ) {
const newImages = event.Records.map(
(record) => AWS.DynamoDB.Converter.unmarshall(record.dynamodb.NewImage)
);
console.log('Converted records', newImages);
callback(null, `Success`);
}
Python
Use TypeDeserializer.deserialize from boto3.dynamodb.types:
import json
from boto3.dynamodb.types import TypeDeserializer
def ddb_deserialize(r, type_deserializer = TypeDeserializer()):
return type_deserializer.deserialize({"M": r})
def lambda_handler(event, context):
new_images = [ ddb_deserialize(r["dynamodb"]["NewImage"]) for r in event['Records'] ]
print('Converted records', json.dumps(new_images, indent=2))
I know is a bit old but I had the same problem processing stream data from dynamoDB in node js lambda function. I used the proposed by #churro
import sdk and output converter
var AWS = require("aws-sdk");
var parse = AWS.DynamoDB.Converter.output;
use the parse function with a small hack
exports.handler = function( event, context, callback ) {
var docClient = new AWS.DynamoDB.DocumentClient();
event.Records.forEach((record) => {
console.log(record.eventID);
console.log(record.eventName);
console.log('DynamoDB Record:', parse({ "M": record.dynamodb.NewImage }));
});
callback(null, `Successfully processed ${event.Records.length} records.`);
}
Hope it helps
AWS JavaScript SDK was recently updated with Document Client which does exactly what you need. Check the announce and usage examples here: http://blogs.aws.amazon.com/javascript/post/Tx1OVH5LUZAFC6T/Announcing-the-Amazon-DynamoDB-Document-Client-in-the-AWS-SDK-for-JavaScript
Javascript: AWS SDK provides the unmarshall function
Python: use TypeDeserializer from boto3.dynamodb.types:
from boto3.dynamodb.types import TypeDeserializer, TypeSerializer
def from_dynamodb_to_json(item):
d = TypeDeserializer()
return {k: d.deserialize(value=v) for k, v in item.items()}
## Usage:
from_dynamodb_to_json({
"Day": {"S": "Monday"},
"mylist": {"L": [{"S": "Cookies"}, {"S": "Coffee"}, {"N": "3.14159"}]}
})
# {'Day': 'Monday', 'mylist': ['Cookies', 'Coffee', Decimal('3.14159')]}
Here you can find gist which does that:
function mapper(data) {
let S = "S";
let SS = "SS";
let NN = "NN";
let NS = "NS";
let BS = "BS";
let BB = "BB";
let N = "N";
let BOOL = "BOOL";
let NULL = "NULL";
let M = "M";
let L = "L";
if (isObject(data)) {
let keys = Object.keys(data);
while (keys.length) {
let key = keys.shift();
let types = data[key];
if (isObject(types) && types.hasOwnProperty(S)) {
data[key] = types[S];
} else if (isObject(types) && types.hasOwnProperty(N)) {
data[key] = parseFloat(types[N]);
} else if (isObject(types) && types.hasOwnProperty(BOOL)) {
data[key] = types[BOOL];
} else if (isObject(types) && types.hasOwnProperty(NULL)) {
data[key] = null;
} else if (isObject(types) && types.hasOwnProperty(M)) {
data[key] = mapper(types[M]);
} else if (isObject(types) && types.hasOwnProperty(L)) {
data[key] = mapper(types[L]);
} else if (isObject(types) && types.hasOwnProperty(SS)) {
data[key] = types[SS];
} else if (isObject(types) && types.hasOwnProperty(NN)) {
data[key] = types[NN];
} else if (isObject(types) && types.hasOwnProperty(BB)) {
data[key] = types[BB];
} else if (isObject(types) && types.hasOwnProperty(NS)) {
data[key] = types[NS];
} else if (isObject(types) && types.hasOwnProperty(BS)) {
data[key] = types[BS];
}
}
}
return data;
function isObject(value) {
return typeof value === "object" && value !== null;
}
}
https://gist.github.com/igorzg/c80c0de4ad5c4028cb26cfec415cc600
If you are using python in the lambda you can utilise the dynamodb-json library.
Install library
pip install dynamodb-json
and use the below snippet
from dynamodb_json import json_util as util
def marshall(regular_json):
dynamodb_json = util.dumps(reular_json)
def unmarshall(dynamodb_json):
regular_json = util.loads(dynamodb_json)
Reference
https://pypi.org/project/dynamodb-json/
I think it's just a custom transformation exercise for each app. A simple conversion from DynamoDB's item format to you application format might look like this:
var response = {...} // your response from DynamoDB
var formattedObjects = response.videos.map(function(video) {
return {
"file": video.file.S,
"id": video.id.S,
"canvas": video.canvas.S
};
});
If you want to build a generic system for this, you would have to handle DynamoDB's various AttributeValue types. A function like the one below would do the job, but I've left out the hard work of handling most of DynamoDB's more complex attribute value types:
function dynamoItemToPlainObj(dynamoItem) {
var plainObj = {};
for (var attributeName in dynamoItem) {
var attribute = dynamoItem[attributeName];
var attributeValue;
for (var itemType in attribute) {
switch (itemType) {
case "S":
attributeValue = attribute.S.toString();
break;
case "N":
attributeValue = Number(attribute.N);
break;
// more attribute types...
default:
attributeValue = attribute[itemType].toString();
break;
}
}
plainObj[attributeName] = attributeValue;
}
return plainObj;
}
var formattedObjects = response.videos.map(dynamoItemToPlainObj);
I tried several solutions here but none worked with multi-level data, such as if it includes a list of maps e.g.
{
"item1": {
"M": {
"sub-item1": {
"L": [
{
"M": {
"sub-item1-list-map": {
"S": "value"
Below, adapted from #igorzg's answer (which also has that drawback), fixes that.
Example usage:
dynamodb.getItem({...}, function(err, data) {
if (!err && data && data.Item) {
var converted = ddb_to_json(data.Item);
Here's the conversion function:
function ddb_to_json(data) {
function isObject(value) {
return typeof value === "object" && value !== null;
}
if(isObject(data))
return convert_ddb({M:data});
function convert_ddb(ddbData) {
if (isObject(ddbData) && ddbData.hasOwnProperty('S'))
return ddbData.S;
if (isObject(ddbData) && ddbData.hasOwnProperty('N'))
return parseFloat(ddbData.N);
if (isObject(ddbData) && ddbData.hasOwnProperty('BOOL'))
return ddbData.BOOL;
if (isObject(ddbData) && ddbData.hasOwnProperty('NULL'))
return null;
if (isObject(ddbData) && ddbData.hasOwnProperty('M')) {
var x = {};
for(var k in ddbData.M)
x[k] = convert_ddb(ddbData.M[k])
return x;
}
if (isObject(ddbData) && ddbData.hasOwnProperty('L'))
return ddbData.L.map(x => convert_ddb(x));
if (isObject(ddbData) && ddbData.hasOwnProperty('SS'))
return ddbData.SS;
if (isObject(ddbData) && ddbData.hasOwnProperty('NN'))
return ddbData.NN;
if (isObject(ddbData) && ddbData.hasOwnProperty('BB'))
return ddbData.BB;
if (isObject(ddbData) && ddbData.hasOwnProperty('NS'))
return ddbData.NS;
if (isObject(ddbData) && ddbData.hasOwnProperty('BS'))
return ddbData.BS;
return data;
}
return data;
}
If you need online editor try this
https://2json.net/dynamo