Fetch, store and use JSON variable with express - javascript

I've been struggling trying to understand how to access and and process data using HTTP method routes (get, put, post...). So far, I've been able to fetch the JSON data and store it in a global variable.
var pokedata;
fetch('https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json')
.then(function (res) {
return res.json();
}).then(function (json) {
pokedata = json;
}).catch(function () {
console.log("It was not possible to fetch the data.")
});
I wanted to send responses HTTP GETs to http://localhost:3000/pokemon/XXX/ with some data about that Pokémon number XXX (which is in the JSON called pokedata). However, any attempt at looping through the data inside GET, triggers the error:
app.get('/pokemon/:pokemonid', function (req, res) {
//not the desired behaviour but a sample of what doesn't work.
for (let {name: n, weight: w, height: h} of pokedata) {
res.send(n, w, h);
}
});
TypeError: pokedata[Symbol.iterator] is not a function
Can't seem to find anything related in the express docs. Any help is well received.

pokedata is an object, and you don't want to iterate on it. Instead you want to iterate on pokedata.pokemon, which is an array of the pokemon. So a small modification to your code is all that's needed:
for (let {name: n, weight: w, height: h} of pokedata.pokemon) {
res.send(n, w, h);
}

Related

Define response structure in Adonisjs with Middleware

I want to define the response structure of my requests in the simplest way, and the first thing that comes in my mind to do this is a middleware.
My endpoints are returning the response content correctly:
{{base_url}}/users returns a list of users:
{
[
{
"id": 44,
"name": "some name"
[...]
}
]
}
What I want to do (in all requests) is to add the fields status and data (or any other I'd like to add), like this:
{
"status": 200,
"data": [
{
"id": 44,
"name": "some name"
[...]
}
]
}
I've created a middleware that waits for the resolution but I'm not able to get the content nor add some property to it.
[...]
async handle ({request, response}, next) {
await next()
const content = response._lazyBody.content
content.status = response.response.statusCode
}
[...]
I know this will not work but I want something similar to this. I've looked in Adonis docs and forum, but no answers fit to my needs.
Any help will be welcome
You can extend Response By extending the core. The simplest way is to create a file inside start folder and name it hooks.js and copy and paste the content below inside it:
const { hooks } = use('#adonisjs/ignitor')
const Response = use('Adonis/Src/Response')
hooks.after.providersBooted(() => {
Response.macro('customJson', function (status, data) {
this.status(status).json({
status,
data
})
})
})
this piece of code extends the Response module and add customJson method to it which takes two arguments, status and data, and send them back to the client.
And here you can see how to use it:
Route.get('/users', async ({ response }) => {
let status = ''// whatever you want
let data = ''// whatever you want
return response.customJson(status, data)
})

continuously store 'get' and store data in mongodb using nodejs

I need to continuously make this http.get request from an API that sends back location data
So i tried writing a basic get reuest to check if the data is coming through, and it is, the problem is I need it in a continuous loop every second the gps device sends data.
http.get(_url2, res =>{
let body='';
res.on("data", data =>{
body+=data;
})
res.on("end",()=>{
body = JSON.parse(body);
gpsData.push(body.data);
console.log('gpsData Array : ',gpsData)
})
})
I get this logged out to the console,
$ node server3.js
gpsData Array : [ [ { imei: '86851212020143921',
device_info: 0,
device_info_new: 0,
seconds: 0,
gps_time: 1548760740,
sys_time: 1548760744,
heart_time: 1548760744,
server_time: 1548760748,
lng: 33.756899,
lat: -13.973598,
course: 160,
speed: 7,
status: '010000fb000000000000000000000000',
location: 'GPS',
acc: '1',
acc_seconds: 335,
voice_status: -1,
voice_gid: 0 } ] ]
showing that it's working
how can I make this code into an asynchronous WebSocket that continuously gets that data, then stores it in MongoDB with given fields?
ok so I found a solution, the best(in my opinion) way is to use setInterval() function, put the HTTP request inside the function to set how many times per unit time you want to insert in the db, then from there mongodb accepts objects by default, so if you return an object to mongodb is will save it for you, here's the code
MongoClient.connect('mongodb://127.0.0.1:27017/gpsapp2', function(err,client){
if(err) return console.log(err)
db = client.db('gpsapp2')
let counter =0
setInterval(()=>{
http.get(_url2, res =>{
let body='';
res.on("data", data =>{
body+=data;
})
res.on("end",()=>{
body = JSON.parse(body);
//console.log(counter++,'Records inserteerd')
db.collection('gpsdata').save(body.data[0]);
})
})
},1000);
http.get from the url, parse the body then save to collection. dont forget the API call is asynchronous so any call for the data outside res.on('end') will get empty or undefined results.
hope this helps somebody.

Node js http server accept POST and accept JSON

I am trying to create one Node js server with http package. I want to receive only POST request which I have already implemented it. The problem which I am facing is that I am not able to parse JSON correctly (I am expecting one JSON to be attached).
I tried using JSON.parse but that doesn't parse whole json content. It leaves some values as [Object] which is wrong. I saw few packages which is JSONStream but I am not sure how to implement in this case.
server.on('request', function(req, res){
if(req.method == 'POST')
{
var jsonString;
req.on('data', function (data) {
jsonString = JSON.parse(data);
});
req.on('end', function () {
serverNext(req, res, jsonString);
});
}
else
{
res.writeHead(405, {'Content-type':'application/json'});
res.write(JSON.stringify({error: "Method not allowed"}, 0, 4));
}
res.end();
});
Request example:
Here d = JSON file content. (I did this in Python to make this example request)
r = requests.post('http://localhost:9001', headers = {'content-type': 'application/json'}, data = json.dumps(d))
Note: I am able to parse JSON correctly but there are some cases when it shows something like this:
{ 'Heading':
{ 'Content':
{ sometext: 'value',
List: [Object], // Wrong
test: [Array] } } } // Wrong
Update:
Inside serverNext() I am getting few values like:
var testReq = Object.keys(jsonData)[0];
var testId = Object.keys(jsonData[testRequest])[0];
var test = jsonData[testRequest][testId]
Further if I keep on extracting values then at some point it encounters [Objects] value and get crashed.
I can reproduce this "problem" with data as { "Foo": {"Bar": {"Some data": [43, 32, 44]} } } -- it returns the following result: { Foo: { Bar: { 'Some data': [Object] } } }.
As OP mentioned in question, the JSON is parsed correctly, the reason why [Object] is displayed in result is: when JavaScript Object is returned to display, it would be converted to String first by toString() automatically, which will make all object (including array) as [Object] in text.
To display the real content, JSON.stringify() need to be invoked. In your case, the code would be:
req.on('end', function () {
serverNext(req, res, JSON.stringify(jsonString));
});
Please note it is better to rename variable jsonString as jsonObject.

Express node.js - Requesting JSON, processing it asyncronously

With my node.js app, I'm getting my JSON data from a spreadsheet API.
It basically returns JSON of the following.
{
"status":200,
"success":true,
"result":[
{
"Dribbble":"a",
"Behance":"",
"Blog":"http://blog.invisionapp.com/reimagine-web-design-process/",
"Youtube":"",
"Vimeo":""
},
{
"Dribbble":"",
"Behance":"",
"Blog":"http://creative.mailchimp.com/paint-drips/?_ga=1.32574201.612462484.1431430487",
"Youtube":"",
"Vimeo":""
}
]
}
It's just a dummy data for now but one thing for certain is that, I need to process values (blog URLs) under Blog differently. With the blog url, I need to get Open Graph data so I'm using a module called open-graph-scraper
With data.js I'm getting the whole JSON and it's available in route index.js as data Then I'm processing this data by checking Blog column. If it's a match, I loop the values (blog URLs) through open-graph-scraper module.
This will give me open graph data of each blog url like the following example JSON.
{
data:
{ success: 'true',
ogImage: 'http://davidwalsh.name/wp-content/themes/punky/images/logo.png',
ogTitle: 'David Walsh - JavaScript, HTML5 Consultant',
ogUrl: 'http://davidwalsh.name/',
ogSiteName: 'David Walsh Blog',
ogDescription: 'David Walsh Blog features tutorials about MooTools, jQuery, Dojo, JavaScript, PHP, CSS, HTML5, MySQL, and more!' },
success: true
}
So my goal is to pass this blog JSON as a separate data from the main JSON and put it in the render as a separate object so it's available in view as two separate JSON. But I'm not sure if my approach with getBlogData is correct.
I'm not even sure if processing data like this is a good thing to do in a router file. I would appreciate some directions.
index.js
var ogs = require('open-graph-scraper');
var data = require('../lib/data.js');
data( function(data) {
var getBlogData = function (callback) {
var blogURL = [];
if (data.length > 0) {
var columnsIn = data[0];
for(var key in columnsIn) {
if (key === 'Blog') {
for(var i = 0; i < data.length; i++) {
blogURL += data[i][key];
}
}
}
};
ogs({
url: blogURL
}, function(er, res) {
console.log(er, res);
callback(res);
});
}
getBlogData( function (blogData) {
//I want to make this blogData available in render below
but don't know how
});
router.get('/', function(req, res, next) {
res.render('index', {
title: 'Express',
data: data
});
});
});
data.js (my module that gets JSON data)
module.exports = function(callback) {
var request = require("request")
var url = "http://sheetsu.com/apis/94dc0db4"
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
var results = body["result"];
callback(results)
}
})
}
The problem you'll have is that if you do getBlogData asynchronously (and you should, you don't want the client waiting around for all that data to return), by the time you get the data res.render will have already been called. As you can't call res.render again, you have 2 options that come to mind:
You could query for individual blog data from the client. This will result in more back-and-forth between client and server but is a good strategy if you have a lot of entries in your initial data but only want to display a small number.
You could use websockets to send the data to the client as you retrieve it. Look up something like express.io for an easy way to do this.

Backbone - Populating multiple models from one fetch call in my controller

Say I have a collection (of search results, for example) which needs to be populated and a pagination model that needs to take values for current page, total number of pages, etc. In my controller, I make a GET call to an API which returns both search results and pagination information. How, then, can I fetch all this information and parse it into a collection and a separate model? Is this possible?
I am using AirBNB's Rendr, which allows you to use a uniform code base to run Backbone on both the server and the client. Rendr forces me to parse the API response as an array of models, keeping me from being able to access pagination information.
In Rendr, my controller would look like this:
module.exports = {
index: function (params, callback) {
var spec = {
pagination: { model: 'Pagination', params: params },
collection: { collection: 'SearchResults', params: params }
};
this.app.fetch(spec, function (err, result) {
callback(err, result);
});
}
}
I apologize if this is not clear enough. Feel free to ask for more information!
This is super old so you've probably figured it out by now (or abandoned it). This is as much a backbone question as a Rendr one since the API response is non-standard.
Backbone suggests that if you have a non-standard API response then you need to override the parse method for your exact data format.
If you really want to break it up, the way you may want to code it is:
a Pagination Model
a Search Results Collection
a Search Result Model
and most importantly a Search Model with a custom parse function
Controller:
index: function (params, callback) {
var spec = {
model: { model: 'Search', params: params }
};
this.app.fetch(spec, function (err, result) {
callback(err, result);
});
}
Search Model
var Base = require('./base'),
_ = require('underscore');
module.exports = Base.extend({
url: '/api/search',
parse: function(data) {
if (_.isObject(data.paginationInfo)) {
data.paginationInfo = this.app.modelUtils.getModel('PaginationInfo', data.paginationInfo, {
app: this.app
});
}
if (_.isArray(data.results)) {
data.results = this.app.modelUtils.getCollection('SearchResults', data.results, {
app: this.app,
params: {
searchQuery: data.searchQuery // replace with real parameters for client-side caching.
}
});
}
return data;
}
});
module.exports.id = 'Search';

Categories