NodeJS and Backbone's fetch - javascript

This is my front-end code (using fetch)
var MyModel = Backbone.Model.extend();
var MyCollection = Backbone.Collection.extend({
url: '/questions',
model: MyModel
});
var coll = new MyCollection();
coll.fetch({
error: function (collection, response) {
console.log('error', response);
},
success: function (collection, response) {
console.log('success', response);
}
});
and this is my back-end code (using app.get)
app.get('/questions', function (request, response) {
console.log('Inside /questions');
response.writeHead(200, {
'Content-Type': 'text/json'
});
response.write('{test:1}');
response.end();
});
The problem is that although the response is as expected, the client-side error callback is called. When I remove the line response.write('{test:1}');, the success callback is called. Any ideas as to what I might be doing wrong?

Well {test:1} is not valid JSON.
{ "test":"1" }
OR
{ "test":1 }
is however, try one of those instead.
Keys are strings in JSON, and strings in JSON must be wrapped in double quotes check out JSON.org for more information.
To ensure you have valid JSON for more complex objects just use JSON.stringify():
var obj = { test : 1 };
response.write(JSON.stringify(obj)); //returns "{"test":1}"
Also, the correct Content-Type for json is application/json

{test:1} isn't valid JSON, you should try { "test":"1" }.
Another solution is to check Express's render.json function to see how it does sending json to the browser:
https://github.com/visionmedia/express/blob/master/lib/response.js#L152-172

If you're using express you need to res.send will automatically convert objects into JSON. If you're worried about it, there's a new one called res.json that will convert anything into JSON.
var obj = {super: "man"}
res.send(obj) // converts to json
res.json(obj) // also converts to json
You don't need need writeHead(), write(), or end().
http://expressjs.com/guide.html

Related

Angular 2 - Http Get request - pass json Object

How can I do a http get request and pass an json Object
This is my json-Object
{{firstname:"Peter", lastname:"Test"}
and this Object I want to pass in the http request to get a list Of matched persons.
how is it possible? This example just shows a simple get request with a json result. How do I have to modify it?
//Component:
person:Person;
persons:Person [];
....
//Whre can I pass the person, here in the service??
getMatchedPersons(){
this.httpService.getMatchedPersons().subscribe(
data => this.persons = data,
error => aller(error)
);
);
//SERVICE
//pass parameters?? how to send the person object here?
getMatchedPersons(){
return this.http.get('url').map(res => res.json());
}
The Http.get method takes an object that implements RequestOptionsArgs as a second parameter.
The search field of that object can be used to set a string or a URLSearchParams object.
An example:
// Parameters obj-
let params: URLSearchParams = new URLSearchParams();
params.set('firstname', yourFirstNameData);
params.set('lastname', yourLastNameData);
//Http request-
return this.http.get('url', {
search: params
}).subscribe(
(response) => //some manipulation with response
);
For pure javascript:
You must serialize your json to a list of parameters:
?firstname=peter&lastname=test
and append it to the URL because GET requests have no body.
There are a few ways of converting JSON to QueryParameters.
They are addressed in this question: Is there any native function to convert json to url parameters?
There you can choose the poison of your liking, mine was:
function obj_to_query(obj) {
var parts = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
}
}
return "?" + parts.join('&');
}
But mind you that GET requests must obbey the URL limit that based on this answer is recomended to stay under 2000 characters to be safe:
RFC says 8000
IE8 and IE9 go as far as 2083
Search engines only read to 2048
Using Angular2 URLSearchParams
With the same method of converting a plain JSON to arguments one could use URLSearchParams as suggested by Рома Скидан:
let params: URLSearchParams = objToSearchParams(obj);
return this.http.get('url', {
search: params
}).subscribe(
(response) => //some manipulation with response
);
function objToSearchParams(obj): URLSearchParams{
let params: URLSearchParams = new URLSearchParams();
for (var key in obj) {
if (obj.hasOwnProperty(key))
params.set(key, obj[key]);
}
return params;
}
Maybe you want to stringify the json object
var json = JSON.stringify(myObj);
this.http.get('url'+'?myobj='+encodeURIComponent(json))
Use a POST request to pass objects to the server:
//SERVICE
getMatchedPersons(searchObj: any){
return this.http.post('url', JSON.stringify(searchObj))
.map(res => res.json());
}
Then you can pass whatever JS object you want and send it to the server in your http request.
getMatchedPersons(searchObj: any){
this.httpService.getMatchedPersons(searchObj: any).subscribe(
data => this.persons = data,
error => alert(error);
);
);
Similar to AngJobs' but maybe more up-to-date?? Calling encodeURIComponent is not necessary. Here's the Angular:
const stringifiedParams = JSON.stringify(this.filterParams);
return this.http.get<any[]>(`persons`, {params: {filter: stringifiedParams}});
On the server Node deserializes the params with JSON.parse:
filter = JSON.parse(req.query.filter.toString());
Actually there's an easier way for flushing parameters
getMatchedPersons(myObject: any): Observable<Person[]> {
return this.http.get<Person[]>('url', { params: { ...myObject } });
}
The above code represents a function that accepts a JSON object myObject as a parameter.
HttpClient.get method accepts an options paramter as its second paramter.
The options parameter contains many useful keys, but we're only interested with the params key in our case.
the value of params is { ...myObject }, that is- we're using the spread operator to pass all key:value pairs from an object.
Refer that this will do the job, and will not make the URL look ugly with all those ? and key=value and & characters, of course in either case those parameters won't be shown for the user since it's just an HTTP call, but still, if anyone is using a logger interceptor, they will have a clean log.

Can't create and pass jsonp data

I am new to Node.js and I have created a method that should asynchronously fetch jsonp data via ajax and display the retrieved content in a graph. This method works fine when the url points to a static js file (in this case productsData.js) containing jsonp data:
function loadChart(destElementId, alertId) {
$.ajax({
url:'http://localhost:3000/products/data/productsData.js',
type: "GET",
data: {prodId: prodId},
jsonp: true,
dataType : 'json',
jsonpCallback: "jsonpCallback"
});
window["jsonpCallback"] = function(data) {
populateData(data, destId);
}
}
As in normal applications, I want to pass real data fetched via an external web service. I have created the following js file (data-client.js) that retrieves data from a specific web service. When calls are browser-based, the data is fetched successfully as a normal json and is displayed accordingly in the browser.
var express = require('express');
var router = express.Router();
var http = require('http');
var yaml_config = require('node-yaml-config');
var config = yaml_config.load(__dirname + '/../config/app-config.yml');
router.get('/data/:id', function (req, res, next) {
var opts = {
host: config.alertService.host,
port: config.alertService.port,
method: 'GET',
path: '/DataService/rest/receiveData/' + req.params.id
}
var reqGet = http.request(opts, function (dataResponse) {
var responseString = '';
dataResponse.on('data', function (data) {
responseString += data;
});
var response = {x:[],y:[],z:[],t:[]};
dataResponse.on('end', function () {
var responseObject = JSON.parse(responseString);
var accs = responseObject.data.listPCS;
for(var i in accs){
response.x.push(accs[i].accX);
response.z.push(accs[i].accY);
response.y.push(accs[i].accZ);
response.t.push(accs[i].timestamp);
}
res.json(response);
});
});
reqGet.end();
reqGet.on('error', function (e) {
console.error(e);
});
});
module.exports = router;
The first step for using live jsonp data is to replace the previous url value with:
url: 'http://localhost:3000/products/data/'+productId,
The second step is to replace in the data-client.js:
res.json(response);
with:
res.jsonp('jsonpCallback('+ JSON.stringify(response) + ');');
Somehow the data is not fetched. When I try to get the data via the browser (i.e. by entering http://localhost:3000/data/ID937) however I get the following result:
"jsonpCallback({\"x\":[1,1,1],\"y\":[2,1,4],\"z\":[0,0,9],\"t\":[1462790772000,1462790772010,1462790772020]});"
Can someone please tell me where the problem may be? I would be very thankful.
It looks like you are using Express.
jsonp() expects to be passed your raw data, not a string containing the complete response. It also expects to read the callback name from the query string, which jQuery will generate for you if you let it.
So the first thing to do is to fix your client side code so it passes the callback name correctly
On the client
$.ajax({
url: 'http://localhost:3000/products/data/' + productId,
dataType: 'jsonp',
}).done(function(data) {
populateData(data, destId);
});
The changes here are:
GET is the default (and, for JSONP, only option) so there is no need to specify the type.
You are passing the data as a URL path part, not a query string. Drop the data property that you aren't using.
The jsonp property is used to override the callback name. That's harmful, don't do that (likewise, don't specify jsonpCallback). jQuery will generate one for you and add it to the query string.
If you are dealing in JSONP then specify that as the data type, not JSON.
Don't create your own global manually. Pass your function to done and let jQuery make it a global (with a generated name to match the callback).
On the server
Just pass the data structure you want to send back to jsonp().
res.jsonp(response);
The callback name will be read from the query string by Express.

Node.js and Express - Sending JSON object from SoundCloud API to the front-end makes it a string

I have been using an http.get() to make calls to the SounbdCloud API method to receive a JSON object that I would like to pass to the browser. I can confirm that the data I receive is an object, since I the typeof() method I call on the data prints out that it is an object.
var getTracks = http.get("http://api.soundcloud.com/tracks.json?q="+query+"&client_id=CLIENT_ID", function(tracks) {
tracks.on('data', function (chunk) {
console.log(typeof(chunk)); // where I determine that I receive an object
res.send(chunk);
});
//console.log(tracks.data);
}).on("error", function(e){
console.log("Got error: "+e);
});
But when I check the data I receive in the AJAX request I make in the browser, I find that the data received has a type of String (again, I know this by calling typeof())
$('#search').click(function(e){
e.preventDefault();
var q = $("#query").val();
$.ajax({
url: '/search',
type: 'POST',
data: {
"query": q
},
success: function(data){
alert(typeof(data));
alert(data);
},
error: function(xhr, textStatus, err){
alert(err);
}
})
});
I would appreciate the help, since I do not know where the problem is, or whether I am looking for the answer in the wrong places (perhaps it has something to do with my usage of SoundCloud's HTTP API)
JSON is a string. I assume you need an Object representing your JSON string.
Simply use the following method.
var obj = JSON.parse(data);
Another example would be:
var jsonStr = '{"name":"joe","age":"22","isRobot":"false"}';
var jsonObj = JSON.parse(jsonStr);
jsonObj.name //joe
jsonObj.age // 22

JavaScript missing parametar

I am coding a block type plugin for Moodle and have this JS code that gives me problems. Since I'm not very familiar with JS and JSON I can't deduce what is the problem.
My code uses this function to add custom action to action link which issues ajax call to php file ...
This is the code:
function block_helpdesk_sendemail(e) {
e.preventDefault();
Y.log('Enetered method');
var sess = {'sesskey=':M.cfg.sesskey};
Y.log(sess);
var ioconfig = {
method: 'GET',
data: {'sesskey=':M.cfg.sesskey},
on: {
success: function (o, response) {
//OK
var data;
try {
data = Y.JSON.parse(response.responseText);
Y.log("RAW JSON DATA: " + data);
} catch (e) {
alert("JSON Parse failed!");
Y.log("JSON Parse failed!");
return;
}
if (data.result) {
alert('Result is OK!');
Y.log('Success');
}
},
failure: function (o, response) {
alert('Not OK!');
Y.log('Failure');
}
}
};
Y.io(M.cfg.wwwroot + '/blocks/helpdesk/sendmail.php', ioconfig);
}
The code pauses in debugger at return line:
Y.namespace('JSON').parse = function (obj, reviver, space) {
return _JSON.parse((typeof obj === 'string' ? obj : obj + ''), reviver, space);
};
I've put M.cfg.sesskey and data variables on watch. I can see sesskey data shown, but data variable shows like this:
data: Object
debuginfo: "Error code: missingparam"
error: "A required parameter (sesskey) was missing"
reproductionlink: "http://localhost:8888/moodle/"
stacktrace: "* line 463 of /lib/setuplib.php: moodle_exception thrown
* line 545 of /lib/moodlelib.php: call to print_error()
* line 70 of /lib/sessionlib.php: call to required_param()
* line 7 of /blocks/helpdesk/sendmail.php: call to confirm_sesskey()"
And this is what my logs show:
Enetered method
Object {sesskey=: "J5iSJS7G99"}
RAW JSON DATA: [object Object]
As #Collett89 said, the JSON definition is wrong. His tip might work, but if you need strict JSON data then code the key as string (with quotes):
var sess = {'sesskey': M.cfg.sesskey};
or
var sess = {"sesskey": M.cfg.sesskey};
See definition in Wikipedia
your declaring sesskey in a bizarre way.
try replacing data: {'sesskey=':M.cfg.sesskey},
with data: {sesskey: M.cfg.sesskey},
it might be worth you reading through this
mdn link for javascript objects.
You usually need to JSON.stringify() the objects sent via ajax.
which may be part of the problem.

prototype js parsing multiple json objects

I am a prototype newbie and am unclear on how to process multiple json objects returned. For example I would like to return a simple JSONObject map indicating the success/failure and also return a JSONArray that I can index and build an select:options from. Now each json object will be upt in the header with a different name. How do I parse that out client-side and alert on a failure name/value else build the select:option element? tia.
Suppose your /someurl service sends a reply like this:
{
"status": "ok",
"data":["apples", "oranges", "bananas"]
}
What I have done here is to combine the two objects into a single object. In the client you can handle it something like this.
new Ajax.Request('/someurl', {
method:'get',
requestHeaders: {Accept: 'application/json'},
onSuccess: function(transport){
var json = transport.responseText.evalJSON();
if(json.status != 'ok')
{
alert('status "'+json.status+'" not ok')
return; // or throw a fit
}
json.data.each(function(elt){
alert(elt); // or display it, whatever
});
}
});

Categories

Resources