My app is Node.js using Express.
Sending this test data from my client using jQuery POST:
{
title: 'hello',
notes: [
{title: 'note 1'},
{title: 'note 2'}
]
}
And this is the result in my server code:
{ title: 'hello', notes: { '0': { title: 'note 1' }, '1': { title: 'note 2' } } }
I want to get the array of notes to insert into my DB as an Array. What am I missing?
As I can't add an answer myself for 8 hours (wtf?) BUT it does not really answer why Express.bodyParser does not parse JSON correctly
Ok I can get it to work by using:
JSON.stringify ( data )
on the client then server side using
JSON.parse( req.rawBody )
This does feel wrong and why does Express.bodyParser not parse JSON correctly?!
On your client:
$.ajax({
type: 'POST',
data: JSON.stringify(data),
contentType: 'application/json',
url: '/endpoint'
});
On your server:
console.log('POST: ',req.body);
The problem is jQuery mucks around with your data before sending it. If you set the right MIME type, than it leaves you free.
Can you post your client side jQuery code, please? By default jQuery will send data as urlencoded, not JSON. See this question's answer for the way to ensure jQuery sends real JSON data.
FYI the express/connect bodyParser middleware simply uses JSON.parse to parse JSON (and qs.parse to parse urlencoded data). I don't think there are any glaring bugs in those code. Thus I think you should double-check the data you are sending from the browser.
I came across this old question when looking for some other nodejs stuff.
It is a common misconception that jQuery.ajax() functions send data using JSON. Data is sent by jQuery as POST data and not a JSON string. As such all data types (including the numbers in your array) are sent as strings.
This means that express parses the 'array' keys as a string, and since an array can't have a string key in javascript without being an object, it is cast to an object.
It all makes sense then; you can use Express.bodyParser to get a result like that, or you can use JSON.parse or even eval('(' + myPostedData + ')') to get a result object without the indexes.
With your current setup, all you need to do is:
for(var j = 0; j < myVariable.notes.length; j++)
{
var currentNode = myVariable.notes[j];
//currentode.title should be 'note 1' for j = 0, etc
}
Related
So i want to fetch from my local data.js file. It looks like this:
{
product_name: [
{'name': 'hello',
'lastName': 'hello'
}, {'name': 'hi',
'lastName': 'hi'}
]
}
Is this valid JSON?
My code that I'm fetching it with looks like this :
fetch('./data.json')
.then(res=> res.json())
.then(text=> console.log(text))
After this, I get an error in my console.log. Also when I go to the network tab and click on data.json It tells me that javascript needs to be enabled, what does that mean? Thank you guys
I might be able to solve your answer.
First things
You must remember to format the JSON so that it is readable by a user, if you are currently developing your program. In production mode, you can skip this step, but it is a good practice.
Next, The JSON you have does not seem to use quotes for keys. This is a must for JSON.
If you don't like the quotes, use json5, JSON's friendlier brother.
Next,
This explains about JSON with fetch.
The Fetch API returns a response stream in the promise. The response stream is not JSON, so trying to call JSON.parse on it will fail. To correctly parse a JSON response, you'll need to use the response.json function. This returns a promise so you can continue the chain.
I see that you have done it, but are forgetting the GET method mentioned in the above post. And, use return keyword to pass the JSON to the next promise. So, your corrected JS code will be:
fetch('./data.json', { method: "GET" })
.then(res => return res.json())
.then(text => console.log(text))
I am not an expert in React, but these are some common things I can correct.
2nd Part of Question
I do not really know why it says JavaScript needs to be enabled. Maybe go to your settings and enable JavaScript? Or, if you use an ad-blocker, try disabling it once and see.
Final Words
I think I have solved a part of your question.
I'm building a rest api using Express NodeJS with mysql. I'm having no issues at all using GET and using req.params.value and passing values using URL parameters.
Now I'm trying to use POST to insert some data into my database. Using POSTMAN I have no problems doing this because obviously you can set the BODY variables to be used. But it dawned on me in my applications I won't be able to use POSTMAN to do this. My quesiton (which may be silly) is how do I pass these BODY variables to my api? Do I still pass them through the url as parameters? If so, would I use req.body.value or req.params.value? Here is my POST code:
// Add new record
router.post('/editablerecords/add', function (req, res) {
let qb_TxnID = req.body.txnid
let type = req.body.type;
let margin = req.body.margin;
if (!qb_TxnID || !type || !margin ) {
return res.status(400).send({ error:true, message: 'Please provide qb_TxnID, type, or margin' });
}
// res.send(qb_TxnID + ' ' + type + ' ' + margin);
connection.query("INSERT INTO pxeQuoteToClose SET ? ", { 'qb_TxnID': qb_TxnID, 'type': type, 'margin': margin }, function (error, results, fields) {
if(error){
res.send(JSON.stringify({"status": 500, "error": error, "response": null}));
//If there is error, we send the error in the error section with 500 status
} else {
res.send(JSON.stringify({ error: false, data: results, message: 'New record has been created successfully.' }));
//If there is no error, all is good and response is 200OK.
}
});
});
Well it depends on how you will make your request, as an XMLHttpRequest call or via a form, but it will definitely not be using params in that case. Here are three options to send data to your API depending on your requirement, in your case I would advice the last one.
1 - You can use a form and make the action point to to your endpoint. In that case you'll have to add a bodyParser middleware for x-www-form-urlencoded data to your express application. If your using the body-parser library it is as simple as app.use(bodyParser.urlencoded([options])). Data will be available in req.body.
2 - You can send all data in your url but in the query string, not the params. For example: https://yourapi.com/editablerecords/add?qb_TxnID=data_id&type=data_type&margin=data_margin. All data will then be available in the req.query object. No need to add any parser.
3 - Last but not least, I would advise to send your data as a json body using an XMLHttpRequest. To help you out you may use a library like axios or fecth but the principle stay the same: you set your body with your data object and you retrieve it on req.bodyon your api. Seeing your code I do assume that your are using a body parser but if that would not be the case, you should add a middleware using app.use(bodyParser.json()).
I hope I have answer your question and that it will help you out.
I am trying to make a HTTP call and my Content-Type is text/plan but I am working with ionic-native/http which only take object and array,here is what I have tried
Error: advanced-http: "data" argument supports only following data types: Array, Object
TestIR(item){
let headers = { 'Content-Type': 'text/plain'};
let sender ='sendir,1:1,0,';
let code = item.keys[10].code;
let body = sender+code;
let url= "http://10.75.0.120/v2/CI00e0148a";
this.httpNative.setDataSerializer( "json" );
this.httpNative.post(url,body,headers).then(val=>
{console.log(val)}).
catch(e=>{console.log(e)})
}
Assumption: The HTTP plugin being used is cordova-plugin-advanced-http, linked from the Ionic Docs.
Setting the Data Serializer to json tells the plugin to expect a javascript object, but the body you are sending is a string
Solution 1
If the API you are sending data to can handle it, set the Data Serializer to "utf8".
this.httpNative.setDataSerializer( "utf8" );
This tells the plugin to expect text.
Solution 2
Change the body to an object before calling POST.
body = JSON.parse(json);
The string you pass to JSON.parse() must be valid json.
Edit : Removed references to a bug that is now fixed
If you are using the cordova-plugin-advanced-http you could also do the following if you only want to set the content type for one request.
const options: any = {
serializer: 'utf8',
method: 'post',
data: 'my string value'
};
this.http.sendRequest('https://mysite', options);
If your response type is json I recommend to parse it by yourself by using JSON.parse.
I was receiving the same error and I tried the #Glen Davies solution, but the error kept and was intermittently.
Sometimes it used to work, sometimes not.
Error: advanced-http: "data" argument supports only following data types: Array, Object
I'm using Ionic 3 application with cordova http plugin in the http-interceptor and after some hours, I've discovered the problem was that even with the serializer being set in the app.component.ts, it was not working.
The solution was moving the:
this.http.setSSLCertMode('pinned');
this.http.setDataSerializer('utf8');
To the constructor inside the HttpInterceptor.
After this, the error was gone.
I have a Node console app. In my app, I am trying to send some data to a third-party web service. I can successfully add data via the third-party web service via POSTMAN. In my Postman, I have a request setup like this:
Headers
api-key
{my key}
Content-Type
application/json
Body
{
"value": [
{
"#operation": "send",
"id":"1",
"name":"Hello",
"position": { "type": "Point", "coordinates": [90.000000, 0.000000] },
"tags":["january", "friends"]
}
]
}
I am now trying to replicate sending this data via Node. In an attempt to do this, I've written the following:
var ops = {
host: 'example.com',
path: '/api/upload?version=2',
method: 'POST',
headers: {
'api-key':'[my key]',
'Content-Type': 'application/json'
}
};
var r = https.request(ops, (res) => {
res.on('data', (d) => {
console.log(res.statusCode);
console.log(res.statusMessage);
});
});
var data = {
"value": [
req.body.record // req is passed in via express
]
};
console.log(data);
r.write(JSON.stringify(data));
r.end();
When the line console.log(data); is executed, I see the following in the console window:
{ value:
[ { '#operation': 'send',
id: '1',
name: 'Hello',
position: [Object],
tags:[Object]
} ] }
I'm not sure if this is a printing problem or an actual problem. Either way, my real issue is that when I send my request, I see the following also printed in the console window:
400
Bad Request
That data looks correct. I don't understand why I'm getting a 400 when I try to send from Node. Yet, it works just fine from Postman. Does it have to do with the quotation marks? I thought JSON.stringify handled that.
What am I doing wrong?
Honestly, unless you have a really good reason not to, just use something like request. It's way easier/cleaner than trying to build it yourself.
I can't answer any more specifically without knowing what the API you're talking to is expecting.
Also, in your res.on('data'), just console.log(req); and see what else is hiding in there; it might help you solve this with your existing code.
I would try
console.log(JSON.stringify(data));
Instead of
console.log(data);
and then decide what is wrong. This will give me full data in way it is sent to server.
Update:
I have made quick experiment and received following output:
{"value":[{"#operation":"send","id":"1","name":"Hello","position":{"type":"Point","coordinates":[90,0]},"tags":["january","friends"]}]}
The difference with the original JSON is in way how the coordinates are sent to the web service (as integers), which can be your problem.
When making this request:
// Subscribe a new account holder to a MailChimp list
function subscribeSomeoneToMailChimpList()
{
var options =
{
"apikey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"id": "xxxxxx",
"email":
{
"email": "me#example.com"
},
"send_welcome": false
};
var mcSubscribeRequest = UrlFetchApp.fetch("https://us4.api.mailchimp.com/2.0/lists/subscribe.json", options);
var mcListObject = Utilities.jsonParse(mcSubscribeRequest.getContentText());
}
This response is returned:
Request failed for https://us4.api.mailchimp.com/2.0/lists/subscribe.json returned code 500. Truncated server response: {"status":"error","code":-100,"name":"ValidationError","error":"You must specify a apikey value"} (use muteHttpExceptions option to examine full response) (line 120, file "v2")
Line 120 is the line on which UrlFetchApp.fetch is called.
The API key is valid (I have tested with simpler API calls that don't include associative arrays). When I append the API key directly to the base URL and remove it from the options, I get an error saying that the list ID is invalid. When I then append the list ID directly to the base URL and remove it from options, I get an error saying that the email address must be in associative array form.
My question is: Using the above format, how does one send requests that contain associative arrays?
The relevant API documentation can be found here.
After further research & tinkering, I was able to solve this:
https://<dc>.api.mailchimp.com/2.0/lists/subscribe.json?apikey=<my_api_key>&id=<my_list_id>&email[email]=test#test.com&merge_vars[FNAME]=John&merge_vars[LNAME]=Doe&double_optin=false&send_welcome=false
Where <dc> should be replaced with the portion after the dash in your API Key. e.g. "us1", "us2", "uk1", etc.
Doing this in javascript exposes your API key to the world. If someone has your key, he/she can make changes to or gain access to your account.
I think I figured out what is going on after reading through the UrlFetchApp.fetch Docs.
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app?csw=1#fetch(String)
It looks like you should be using some of the extra params to do the request such as payload and method. Your options variable should look like this.
var payload = {
"apikey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"id": "xxxxxx",
"email": {
"email": "me#example.com"
},
"send_welcome": false
};
payload = Utilities.jsonStringify(payload); // the payload needs to be sent as a string, so we need this
var options = {
method: "post",
contentType: "application/json", // contentType property was mistyped as ContentType - case matters
payload: payload
};
var result = UrlFetchApp.fetch("https://<dc>.api.mailchimp.com/2.0/lists/subscribe.json", options);
Where <dc> should be replaced with the portion after the dash in your API Key. e.g. "us1", "us2", "uk1", etc.
The issue is that your options variable is suppose to be used as JSON and not as a GET url parameter. Also mailchimp specifies that it is better to use POST instead of GET. So over all you should make sure to set you method to "post" and make sure your payload is valid JSON.