NodeJS request doesn't encode the entire form - json

The task is rather simple, I request the endpoint with POST request (https://banana.com/endpoint/swap.php), give it my form: { banana: ["China's Red", "Sweden's Gray"], apples: [] } and send it.
However, the Request module for NodeJS that I am using does not encode the empty array (in this case "apples") and if the endpoint doesn't receive the "apples" array, it returns an error - "Invalid JSON". I have tried doing this with already encoded strings and it works just fine. I am also unable to stringify my json and then use encodeURI(), as it will then give "bananas" and "apples" quotes around them, which will get encoded - needless to say, the endpoint doesn't like that either.
I'd really appreciate if somebody could at least point me in the right direction. As I am unsure on how to proceed with this, without creating some awful spaghetti code.

data = { banana: ["China's Red", "Sweden's Gray"], apples: [] }
result = JSON.parse(JSON.stringify(data)) .
You wouldn't get double around banana and apple and if you need to access then access it
console.log(result.banana)
console.log(result.apple)
So if you need to feed this result in post request then -
url = 'your url';
const options = {
url: url,
method: 'POST',
headers: {
Accept: 'application/json',
'Accept-Charset': 'utf-8'
},
json: result
};
request.post(options, function (err, response, body) {
// do something with your data
})
Let me know if this works.

Related

Flutter POST json request body is empty/null on server side

I am sending a post request from my flutter to a localhost api. However, the body on the server side is always empty/null. Whereas, if I send the exact same request on postman everything works fine.
String json = jsonEncode(toCheck);
Map<String,String> headers = {
"Accept": "application/json",
"content-type": "application/json",
};
var response = await http.post(
Uri.parse(userPath + 'validateUser/'),
headers: headers,
body: "{\"email\":\"david#hotmail.com\",\"username\":\"\",\"mobile_phone_number\":\"\",\"password\":\"david\"}");
print(response.statusCode);
if(response.statusCode == HttpStatus.ok){
return response.body as bool;
}
print(response.body.toString());
return false;
The status code is always 500 with the following error:
{"Message":"An error has occurred.","ExceptionMessage":"The value cannot be null"...
This error happens because the parameter "json" is null:
[HttpPost]
[Route("validateUser/", Name = "validadeUser")]
public async Task<IHttpActionResult> ValidateUser([FromBody] string json)
{
//get the username and password to validate the user
UserClient client = JsonConvert.DeserializeObject<UserClient>(json); //error happens here because the string json is null
//...
}
However, when making the same exact request on postman, everything is okay:
The host on the android emulator app is the following:
https://10.0.2.2:44304/api/user/validateUser/
PS: looks like a duplicate of Flutter POST request body is empty on server side and Flutter Dart HTTP POST request body is empty on server side but none of those solutions have worked for me, therefore I posting a new question.
It took me a while to spot the error... but in the end, I did!
Your API takes a String argument from the request body:
ValidateUser([FromBody] string json)
That may seem alright at first, since indeed, you are sending a json String as your request body. But the thing is that since you're also using these headers:
{
"Accept": "application/json",
"content-type": "application/json",
}
This bit: "content-type": "application/json" will translate your correctly formatted json String into an actual json Object! So when it reaches your API, it will no longer be a String, and so your API won't be able to receive it properly.
The solution would be to either remove the "content-type": "application/json" from your headers and keep the request body and the API function as they are, or to change the API to:
ValidateUser([FromBody] object json)
The latter is probably the most convenient, since you were going to parse it from json String to json Object anyway! 🙂
(With this API function, you COULD also remove your "content-type": "application/json" bit from the headers, and then send the request body like this:
body: jsonDecode("{\"email\":\"david#hotmail.com\",\"username\":\"\",\"mobile_phone_number\":\"\",\"password\":\"david\"}"),
Or just not jsonEncode it in the first place... Just send it as an object. This will have the same effect as sending it as a json String with "content-type": "application/json" in the header.)
Btw, as a general rule, make sure you add lots of print and log statements in your code as you develop it! It will help you spot anything that didn't go quite as you had expected, along the way. 😉 (That's how I spotted this.)
Before sending the request to the server please encode your object to complete the body property of the request. Try this:
body: json.encode({\"email\":\"david#hotmail.com\",\"username\":\"\",\"mobile_phone_number\":\"\",\"password\":\"david\"})
Cheers.

NativeScript Throwing Error Response with status: 200 for URL: null

I am using Angular4 with TypeScript version 2.2.2
My web app is running fine when I call JSON with Filters but my NativeScript app fails when I call the Filter Values as an Object but works fine when I call filter values as a string.
Error Response with status: 200 for URL: null
THIS WORKS
https://domainname.com/api/v1/searchevents?token=057001a78b8a7e5f38aaf8a682c05c414de4eb20&filter=text&search=upcoming
If the filter value and search value is STRING it works whereas if they are objects as below, it does not work
THIS DOES NOT WORK
https://api.domainname.com/api/v1/searchevents?token=057001a78b8a7e5f38aaf8a682c05c414de4eb20&filter={"limit":"12","skip":"0"}&search={"search":"","latitude":"","longitude":"","categories":"","address":"","type":"upcoming"}
The Code I used is below
getData(serverUrl, type, skip_limit) {
console.log(serverUrl);
let headers = this.createRequestHeader();
let token_value = localStorage.getItem('access_token')
let url;
var filter;
filter = '{"limit":"10","skip":"0"}'
url = this.apiUrl + serverUrl + '?token=' + token_value + '&filter=' + filter
return this.http.get(url, { headers: headers })
.map(res => res.json());
}
The URL as formed above for the API is fine and works fine. Yet the error comes Error Response with status: 200 for URL: null
CAN ANYONE HELP ME SOLVE THIS?
Looks like the issue is the "filter" values are of different type and from what you mentioned as what worked, your service is expecting a string and not an object/array. So it fails to send the proper response when it gets one. With an object in the URL, you may have to rewrite the service to read it as an object (parse the two attributes and get them individually)
To make it simple, you can make these two as two different variables in the URL. like below,
https://api.domainName.in/api/v1/oauth/token?limit=10&skip=0
Be more precise in whats happening in your question,
1) Log the exact URL and post it in the question. No one can guess what goes in "text" in your first URL.
2) Your URL which you mentioned as worked have "token" as part of path, but in the code, its a variable which will have a dynamic value from "token_value".
3) Post your service code. Especially the signature and input parsing part.
Got the solution:
All you have to do is encode the Filter and Search Parameters if it is an Object or Array using Typescript encodeURI()
var filter = '{"limit":"12","skip":"0"}'
var search = '{"search":"","latitude":"","longitude":"","categories":"","address":"","type":"upcoming"}'
var encoded_filter = encodeURI(filter);
var encoded_search = encodeURI(search);
url = this.apiUrl+serverUrl+'?token='+token_value+'&filter='+encoded_filter+'&search='+encoded_search

Golang net/http request Body always empty

I'm trying to send JSON arguments to my server and parse them using json.Decoder. I've read that you should be able to get the query params from the request.Body property. The following is my server code:
func stepHandler(res http.ResponseWriter, req *http.Request) {
var v interface{}
err := json.NewDecoder(req.Body).Decode(&v)
if err != nil {
// handle error
}
log.Println(v)
}
Every time, I see 2014/12/26 22:49:23 <nil> (diff timestamps, of course). My client-side AJAX call is the following:
$.ajax({
url: "/step",
method: "get",
data: {
steps: $("#step-size").val(),
direction: $("#step-forward").prop("checked") ? 1 : -1,
cells: JSON.stringify(painted)
},
success: function (data) {
painted = data;
redraw();
},
error: function (xhr) {
console.log(xhr);
}
});
An example URL of what is sent:
http://localhost:5000/?steps=1&direction=1&cells=%5B%7B%22row%22%3A11%2C%22column%22%3A15%7D%2C%7B%22row%22%3A12%2C%22column%22%3A15%7D%5D
A nicer look at the params:
{
steps: "1",
direction: "1",
cells: "[{"row":11,"column":15},{"row":12,"column":15}]"
}
I have tried with both GET and POST requests.
Why does my req.Body never decode? If I try to print req.Body alone, I also see nil.
req.Body is indeed empty -- so, what I would do it call req.ParseForm() and then use req.Form instead. Body will not get stuff (such as, query parameters) that's definitely not in the request's body.
The Body of a request is sent along inside the payload - it is not part of the URL.
You're attempting to access the body .. when really your data is in the URL.
What you want it to change your ajax method: "get" to be method: "post" - so that the data is posted along with the body and not as part of the URL. You should also make sure that the data is indeed being sent along with the request via your browser of choice' developer tools. Alternatively, if you really do want your data sent along as part of the URL, you should be accessing the URL parameter of the request - and manually parsing the values into a struct (the json package won't do this for you IIRC).

Playframework handling post request

In my routes:
POST /forms/FormValidator1/validateForm controllers.FormValidator1.validateForm(jsonForm:String)
There is a controller method defined for that route:
def validateForm(jsonForm:String) = Action { ...
Then I try to send POST request by chrome POSTMAN plugin (see pic above).
I use:
url: http://localhost:9000/forms/FormValidator1/validateForm
headers: Content Type: application/json
json data: {name: "me", surname: "my"}
So, sending this POST request I can not reach controller's method by mentioned route / url. Why?
UPDATE:
Interestly enough: after I got it working on my laptop (see my answer below) then push it on gitHub and pull it to another machine it starts working differently. Now it complains than Bad Request is [Invalid XML] nevertheless I use "application/json" header and did not change any line of code after commit. I wonder maybe it is a bug.
It seems I got it.
Here:
https://groups.google.com/forum/#!topic/play-framework/XH3ulCys_co
And here:
https://groups.google.com/forum/#!msg/play-framework/M97vBcvvL58/216pTqm22HcJ
There is wrong and correct way explained:
Doesn't work: curl -d "name=sam" http://localhost:9000/test
Works: curl -d "" http://localhost:9000/test?name=sam
This is the way how POST params are passing..in play. (second link is explanation WHY):
Sometimes you have to make compromises. In Play 1 you could bind your
action parameters from any parameter extracted from the URL path,
query string or even the request body. It was highly productive but
you had no way to control the way the form was uploaded. I mean, if a
user uploads a big file you needed to load the entire request in
memory to be able to handle it.
In Play 2 you can control the request body submission. You can reject
it early if something is wrong with the user, you can process big
files or streams without filling your memory with more than one HTTP
chunk… You gain a high control of what happens and it can help you to
scale you service. But, the other side of the coin is that when a
request is routed, Play 2 only uses the request header to make its
decision: the request body is not available yet, hence the inability
to directly bind an action parameter from a parameter extracted from
the request body.
UPDATE:
Interestly enough: after I got it working on my laptop then push it on gitHub and pull it to another machine it starts working differently. Now it complains than Bad Request is [Invalid XML] nevertheless I use "application/json" header and did not change any line of code after commit.
UPDATE 2
So I fixed it like this:
On angular side (we even can comment dataType and headers):
var data = $scope.fields
$http({
url: '/forms/FormValidator1/validateForm',
method: "POST",
//dataType: "json",
data: data,
//headers: {'Content-Type': 'application/json'}
}).success(function (data, status, headers, config) {
console.log("good")
}).error(function (data, status, headers, config) {
console.log("something wrong")
});
On playFramework side: (use BodyParser)
def validateForm = Action { request =>
val body: AnyContent = request.body
val jsonBody: Option[JsValue] = body.asJson
// Expecting text body
jsonBody.map { jsValue =>
val name = (jsValue \ "name")
val surname = (jsValue \ "surname")
....
}
Routes (don't define parameters at all !):
POST /forms/FormValidator1/validateForm controllers.FormValidator1.validateForm

Angularjs - equal sign in $http post data

I'm using angularjs' $http service to post data to my API. It works great.. until I add and equals sign to the contents of data (JSONRequest in example)
var request = {
'method': 'POST',
'url': API_URL + apiActionName,
'data': JSONRequest,
'withCredentials': true,
};
$http(request).
success(function(data, status, headers, config) {
// handle success
}).
error(function(data, status, headers, config) {
// handle error
}
this works for data contain the following JSONRequest
{
'text':'this is some text'
}
however when the data contains this
{
'text':'this is = some text'
}
the request is escaped and the server cannot do anything with the POST!! It seems to work with all other characters.
Any help would be greatly appreciated! Thanks
I always use JSON.Stringify() for my POST payloads.
It had to do with URI encoding. The string that was getting getting sent the the lower level AJAX API was not uri encoded. This means that when it saw the = sign in the post it was parsing it assuming uri encoding.
All of the information may not have been present to answer this question as JSONRequest was originally was defined on the line above var request. Sorry about that. It was defined as follows:
var JSONRequest = {
'JSON': requestObject;
}
where requestObject was
{
'text':'this is = some text'
}
I ended up URI encoding the JSON Request as follows
var JSONRequest = 'JSON=' + encodeURIComponent(JSON.stringify(requestObject));
This fixed the problem and made my API calls more robust to the HTTP protocol.
Thanks for all the help!!