Struggling to get data from AWS lambda JSON - json

I'm working on a lambda project and getting data from an API inside the function which looks like this
{ "Title": "300", "Year": "2006", "Rated": "R", "Released": "09 Mar 2007", "Runtime": "117 min", "Genre": "Action, Fantasy, War", "Director": "Zack Snyder", "Writer": "Zack Snyder (screenplay), Kurt Johnstad (screenplay), Michael B. Gordon (screenplay), Frank Miller (graphic novel), Lynn Varley (graphic novel)", "Actors": "Gerard Butler, Lena Headey, Dominic West, David Wenham", "Plot": "King Leonidas of Sparta and a force of 300 men fight the Persians at Thermopylae in 480 B.C.", "Language": "English", "Country": "USA, Canada, Bulgaria", "Awards": "17 wins & 45 nominations.", "Poster": "https://m.media-amazon.com/images/M/MV5BMjc4OTc0ODgwNV5BMl5BanBnXkFtZTcwNjM1ODE0MQ##._V1_SX300.jpg", "Ratings": [ { "Source": "Internet Movie Database", "Value": "7.7/10" }, { "Source": "Rotten Tomatoes", "Value": "60%" }, { "Source": "Metacritic", "Value": "52/100" } ], "Metascore": "52", "imdbRating": "7.7", "imdbVotes": "691,774", "imdbID": "tt0416449", "Type": "movie", "DVD": "31 Jul 2007", "BoxOffice": "$210,500,000", "Production": "Warner Bros. Pictures", "Website": "http://300themovie.warnerbros.com/", "Response": "True" }
I've tried dot notation, indexing all sorts but no matter what I try, the console log just comes out with
2019-06-14T18:33:46.394Z ecc5d247-6475-464e-8dd7-bec310d98c4a INFO undefined
Has anyone else had the same issue before with lambda and lex?
Thanks
const https = require('https')
let url = "http://www.omdbapi.com/?t=300&r&apikey=3ecc35a"
let reply;
const http = require('http')
let test;
http.get(url, res => {
res.setEncoding("utf8");
let body = "";
res.on("data", data => {
body += data;
});
res.on("end", () => {
console.log(body);
reply = JSON.parse(body);
});
});
This currently produces a perfectly good JSON in the console but it's impossible to actually extract anything. I've tried reply.Year, reply["Year"], reply.[0].Year almost any combination I can think off.
Full Code
'use strict';
'use fetch';
// Close dialog with the customer, reporting fulfillmentState of Failed or Fulfilled ("Thanks, your pizza will arrive in 20 minutes")
function close(sessionAttributes, fulfillmentState, message) {
return {
sessionAttributes,
dialogAction: {
type: 'Close',
fulfillmentState,
message,
},
};
}
// --------------- Events -----------------------
function dispatch(intentRequest, callback) {
console.log(`request received for userId=${intentRequest.userId}, intentName=${intentRequest.currentIntent.name}`);
const sessionAttributes = intentRequest.sessionAttributes;
//const film = intentRequest.currentIntent.film;
const film = intentRequest.currentIntent.slots.film.toString();
console.log(intentRequest.currentIntent.slots.film.toString());
const https = require('https')
let url = "http://www.omdbapi.com/?t=300&r&apikey=3ecc35a"
let reply;
const http = require('http')
let test;
http.get(url, res => {
res.setEncoding("utf8");
let body = "";
res.on("data", data => {
body += data;
});
res.on("end", () => {
console.log(body);
reply = JSON.parse(body);
});
});
//const rating = reply.imdbRating;
console.log(reply);
callback(close(sessionAttributes, 'Fulfilled',
{'contentType': 'PlainText', 'content': `The film ${film} has a rating of `}));
}
// --------------- Main handler -----------------------
// Route the incoming request based on intent.
// The JSON body of the request is provided in the event slot.
exports.handler = (event, context, callback) => {
try {
dispatch(event,
(response) => {
callback(null, response);
});
} catch (err) {
callback(err);
}
};

I tried to reproduce the issue with that code and got the following error
Response:
{
"errorType": "TypeError",
"errorMessage": "Cannot read property 'name' of undefined",
"trace": [
"TypeError: Cannot read property 'name' of undefined",
" at dispatch (/var/task/index.js:20:112)",
" at Runtime.exports.handler (/var/task/index.js:65:9)",
" at Runtime.handleOnce (/var/runtime/Runtime.js:63:25)",
" at process._tickCallback (internal/process/next_tick.js:68:7)"
]
}
Line 20 of index.js for me is:
console.log(`request received for userId=${intentRequest.userId}, intentName=${intentRequest.currentIntent.name}`);
However when using the test event in the question event.currentIntent doesn't exist and the name property of the event object doesn't exist either.
If I remove part of the console.log statement and change it to reference the Title attribute which exists in the test event I get:
console.log(`request received for Title=${intentRequest.Title}`);
INFO request received for Title=300
Seems like the function's code is referencing attributes fine but the function's just not receiving it's expected event objects.
HTH
-James

Related

Parsing objects of a JSON for input validation

I want to use a database of valid ICAO and IATA airport codes for a discord bot input in typescript. However, I am not quite sure how to call the "icao" and "iata" contstructor of all objects, as each one is defined differently and there are thousands: e.g.:
"00AK": {
"icao": "00AK",
"iata": "",
"name": "Lowell Field",
"city": "Anchor Point",
"state": "Alaska",
"country": "US",
"elevation": 450,
"lat": 59.94919968,
"lon": -151.695999146,
"tz": "America\/Anchorage"
},
"00AL": {
"icao": "00AL",
"iata": "",
"name": "Epps Airpark",
"city": "Harvest",
"state": "Alabama",
"country": "US",
"elevation": 820,
"lat": 34.8647994995,
"lon": -86.7703018188,
"tz": "America\/Chicago"
},
The bot uses the following to provide the METAR of a specific airport:
name: 'metar',
description: 'Provides the METAR report of the requested airport',
category: CommandCategory.UTILS,
executor: async (msg) => {
const splitUp = msg.content.replace(/\.metar\s+/, ' ').split(' ');
if (splitUp.length <= 1) {
await msg.reply('please provide an ICAO airport code.');
return Promise.resolve();
}
const icaoArg = splitUp[1];
if (icaoArg.length !== 4) {
await msg.reply('please provide an ICAO airport code.');
return Promise.resolve();
}
request({
method: 'GET',
url: `https://avwx.rest/api/metar/${icaoArg}`,
headers: {
Authorization: process.env.METAR_TOKEN },
}, async (error, response, body) => {
const metarReport = JSON.parse(body);å
const metarEmbed = makeEmbed({
title: `METAR Report | ${metarReport.station}`,
description: makeLines([
'**Raw Report**',
metarReport.raw,
,
'**Basic Report:**',
`**Time Observed:** ${metarReport.time.dt}`,
`**Station:** ${metarReport.station}`,
`**Wind:** ${metarReport.wind_direction.repr} at ${metarReport.wind_speed.repr}kts`,
`**Visibility:** ${metarReport.visibility.repr}${metarReport.units.visibility}`,
`**Temperature:** ${metarReport.temperature.repr}C`,
`**Dew Point:** ${metarReport.dewpoint.repr}C`,
`**Altimeter:** ${metarReport.altimeter.value.toString()} ${metarReport.units.altimeter}`,
]),
fields: [
{
name: 'Unsure of how to read the raw report?',
value: 'Type \'**.metarhow**\' to learn how to read raw METARs',
inline: false
},
],
footer: { text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.' },
});
await msg.channel.send({ embeds: [metarEmbed] });
});
},
};
Currently, if a user provides an ICAO that's not valid the bot crashes, or if they provide a valid IATA, the discord api throws the user an error to provide a valid ICAO code. How would I go about cross referencing the user argument with the JSON so the bot does not crash when inputting an invalid ICAO? Thanks

AngularJS $scope is undefined outside of .then function

I have a a form which includes select input but the thing is ng-options is not working
Select code
<select ng-model="selectedGender" ng-options="item.value for item in genderData">
I got the data from
ReferenceService.searchCategory("GENDER").then(function (response){
$scope.genderData = response.data;
console.log($scope.genderData);
})
This is the console.log($scope.genderData)
Array(2)
0:{referenceId: 1, category: "GENDER", key: "GENDER_KEY", value: "Male", $$hashKey: "object:3"}
1:{referenceId: 2, category: "GENDER", key: "GENDER_KEY", value: "Female", $$hashKey: "object:4"}
length:2
__proto__
:
Array(0)
but I have tried hard coding the data
$scope.genderData= [
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere#april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
}
];
and it worked! but I used ng-options="item.name for item in genderData">
btw don't mind the data I just searched it for fast use
EDIT:
I think I found the problem. Why is it undefined outside the function?
check this console
line 244 is undefined but line 242 is not?
store the response in var then out side the function assign that var to $scope. it is a callback issue.
If still it's showing same you can use localsorage to store and get the data. but this approach is not recomanded in angularjs. but if nothing happen then you can use this approcah also
That's because ReferenceService.searchCategory("GENDER") returns a promise.
A promise will wait until the data is resolved, and then move on to its success function callback. Which is the .then(function(response)).
So the code will get to the console.log on line 244 before the promise has finished, and $scope.genderData has been created and therefore is undefined
The console.log on line 242 will wait until the promise has been resolved, and calls the success callback function.
UPDATE:
Here an example how to correctly link the $scope to the factory.
Note that you must link to the object and not to its properties in your $scope.
Wrong:
$scope.gender = ReferenceService.data.genderData;
Correct:
$scope.gender = ReferenceService.data;
Example:
myApp.factory('ReferenceService',
function ()
{
var ReferenceService = {
// This is the global object. Link the $scope to this object
data: {
genderData: {}
},
searchCategory: function (type)
{
var getData = $http.get("URL", { params: { gender: type } }).then(
function (response)
{
// Store the data in the factory instead of the controller
// You can now link your controller to the ReferenceService.data
ReferenceService.data.genderData = response.data;
}
)
return getData;
}
}
return ReferenceService;
}
);
myApp.controller('MyController',
function ($scope, ReferenceService)
{
// Link $scope to data factory object
$scope.gender = ReferenceService.data;
// Now you only have to call the factory function
ReferenceService.searchCategory("GENDER");
// This will now log the correct data
console.log($scope.gender.genderData);
}
)

git log in JSON - send changelog to browser

In order to know what's actually been committed to a project in production, we are going to display the Git log to admins - this serve as a makeshift changelog.
I have this routine on a Node.js Express server:
router.get('/changelog/json', ac.allow('ROLE_ADMIN'), function (req, res, next) {
const k = cp.spawn('bash');
k.stdin.write('git log --pretty=format:\'{%n "commit": "%H",%n "abbreviated_commit": "%h",%n "tree": "%T",%n "abbreviated_tree": "%t",%n "parent": "%P",%n "abbreviated_parent": "%p",%n "refs": "%D",%n "encoding": "%e",%n "subject": "%s",%n "sanitized_subject_line": "%f",%n "body": "%b",%n "commit_notes": "%N",%n "verification_flag": "%G?",%n "signer": "%GS",%n "signer_key": "%GK",%n "author": {%n "name": "%aN",%n "email": "%aE",%n "date": "%aD"%n },%n "commiter": {%n "name": "%cN",%n "email": "%cE",%n "date": "%cD"%n }%n},\'\n')
k.stdin.end();
k.stdout.pipe(res);
});
this sort of works, but we don't actually get a JSON array, we just get comma separate JSON strings.
I got this info form here:
https://gist.github.com/varemenos/e95c2e098e657c7688fd
https://git-scm.com/docs/pretty-formats
does anyone know how I can construct a JSON array from the stdout from the Git command?
I tried this:
router.get('/json', ac.allow('ROLE_ADMIN'), function (req, res, next) {
const p = createParser();
const k = cp.spawn('bash', [], {
cwd: global.cdtProjectRoot
});
const items = [];
k.stdin.write('git log --pretty=format:\'{%n "commit": "%H",%n "abbreviated_commit": "%h",%n "tree": "%T",%n "abbreviated_tree": "%t",%n "parent": "%P",%n "abbreviated_parent": "%p",%n "refs": "%D",%n "encoding": "%e",%n "subject": "%s",%n "sanitized_subject_line": "%f",%n "body": "%b",%n "commit_notes": "%N",%n "verification_flag": "%G?",%n "signer": "%GS",%n "signer_key": "%GK",%n "author": {%n "name": "%aN",%n "email": "%aE",%n "date": "%aD"%n },%n "commiter": {%n "name": "%cN",%n "email": "%cE",%n "date": "%cD"%n }%n},\'\n')
k.stdin.end();
k.stdout.pipe(p).on('data', function (d) {
// d would be a parsed JSON object
items.push(d);
})
.once('error', next)
.once('end', function () {
res.json({
success: items
})
})
});
My parser transform works, because I use it in another project, so it's something about the format of the JSON coming from the stdout that's causing the problem - the 'data' event handler never sees any data.
This worked for me, I had to improve the git log format option:
router.get('/json', ac.allow('ROLE_ADMIN'), function (req, res, next) {
const p = createParser();
const k = cp.spawn('bash');
let items = [];
k.stdin.write(`git log -300 --pretty=format:'{"commit":"%H","sanitized_subject_line":"%f","commit_notes":"%N","author":"%aN","date":"%aD"}'`);
k.stdin.end('\n');
k.stdout.pipe(p).on('data', function (d) {
items.push(JSON.parse(d));
})
.once('error', next)
.once('end', function () {
res.json({
success: items
})
})
});
createParser looks like this:
const stream = require("stream");
exports.createParser = function () {
let lastLineData = '';
let strm = new stream.Transform({
objectMode: true,
transform: function (chunk, encoding, cb) {
let _this = this;
let data = String(chunk);
if (lastLineData) {
data = lastLineData + data;
}
let lines = data.split('\n');
lastLineData = lines.splice(lines.length - 1, 1)[0];
lines.forEach(function (l) {
l && _this.push(l);
});
cb();
},
flush: function (cb) {
if (lastLineData) {
this.push(lastLineData);
}
lastLineData = '';
cb();
}
});
return strm;
};
this might barf if there are certain characters in the git log fields, like Author, but I think the built-in field "sanitized_subject_line" will save our skin a bit when it comes to removing bad chars from commit messages.

Spotify API top-tracks broken

I'm trying to get the first top-track preview url from an artist but everytime I do the search it returns a broken json. I can parse it as a string to get what I need but a json would be a lot easier. Here is my code:
const https = require('https');
var open = require('open')
function songError(){
console.log('There was some kind of error fetching your artist ;(');
}
function getTopSong(p_id){
https.get('https://api.spotify.com/v1/artists/'+p_id+'/top-tracks?country=BR', function(res){
res.on("data", function(chunk){
var json = JSON.parse(chunk.toString('utf8'));
console.log(json);
});
});
}
function getArtistID(p_name) {
https.get('https://api.spotify.com/v1/search?q='+encodeURI(p_name)+'&type=artist', function(res){
res.on("data", function(chunk) {
var json = JSON.parse(chunk.toString('utf8'));
if(json['artists']['items'][0]['id'] != undefined || json['artists']['items'][0]['id'] != null){
console.log('id: ',json['artists']['items'][0]['id']);
getTopSong(json['artists']['items'][0]['id']);
}else
{
songError();
}
});
});
}
getArtistID("rage against the machine");
There seems to be an error in line 329:
undefined:329
"available_markets" : [ "AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "
My question is, am I doing something wrong or is it really broken?
Thanks!
I could curl it without any problems at least:
$ curl -s 'https://api.spotify.com/v1/artists/2d0hyoQ5ynDBnkvAbJKORj/top-tracks?country=BR' | python -mjson.tool | tail
"id": "25CbtOzU8Pn17SAaXFjIR3",
"name": "Take The Power Back - Remastered",
"popularity": 58,
"preview_url": "https://p.scdn.co/mp3-preview/b44e8f96a219871587d0559970ca5dce71c891f2",
"track_number": 3,
"type": "track",
"uri": "spotify:track:25CbtOzU8Pn17SAaXFjIR3"
}
]
}
I don't know much about nodejs, but don't you need to concatenate all callbacks to res.on("data"?
https://nodejs.org/api/http.html#http_http_request_options_callback
https.get('https://api.spotify.com/v1/artists/' + p_id + '/top-tracks?country=BR', function(res) {
var body = [];
res.on("data", function(chunk) {
body.push(chunk);
});
res.on("end", function() {
var json = JSON.parse(Buffer.concat(body).toString("utf8"));
console.log(json);
});
});
If the response is long and Spotify's servers decides to send the response back chunked transfer encoding, then the nodejs http module probably splits the response up as well.

backbone collection fetch error

I'm trying to fetch a collection from a .json file. Here is my collection code
define(['jquery', 'underscore', 'backbone', 'vent'], function($, _, Backbone, vent) {
'use strict';
var Wine = Backbone.Model.extend({
urlRoot: "js/models/wines.json",
defaults: {
"id": null,
"name": "",
"grapes": "",
"country": "USA",
"region": "California",
"year": "",
"description": "",
"picture": ""
}
});
return Backbone.Collection.extend({
model: Wine,
url: "js/models/wines.json",
});
});
I'm fetching the collection like this:
var _wine = new wineCollection();
_wine.fetch({
success : function(data) {
console.log("ON SUCCESS");
console.log(data);
},
error: function(response) {
console.log("ON ERROR");
console.log(response);
}
});
In the console it's always showing the "ON ERROR" message:
ON ERROR
child
_byCid: Object
_byId: Object
_callbacks: Object
length: 0
models: Array[0]
__proto__: ctor
And here is one item of my wines.json file
{"id":"9","name":"BLOCK NINE","year":"2009","grapes":"Pinot Noir","country":"USA","region":"California","description":"With hints of ginger and spice, this wine makes an excellent complement to light appetizer and dessert fare for a holiday gathering.","picture":"block_nine.jpg"}
What am I doing wrong?
Have you tried inspecting the collection class in the fetch method (what is actually send over).
You might need to override the parse method in order to access an inner part of the data send over.
For instance:
Wine.Collection = Backbone.Collection.extend({
//we need to parse only the inner list
parse : function (response) {
this.cursor = response.cursor;
return response.list;
}
Where the array is an inner list: {list: [{item: one}, {item: two}]}