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

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.

Related

How to allow Cors Headers in Google AppScript for making an XMLHttpRequest?

I have created a doGet and doPost endpoints in my appscript. When I hit the endpoint to make a post request from Python, it does work perfectly and as expected.
But when I try to hit the same url with my Flutter based mobile App, it throws me an XML error. (Which I suspect is related to CORSING).
When I hit the url with get request, I get the right response, but post request is failing. To ensure that my Post request is properly configured, I have made a post request to public API and it worked like charm.
Is it possible to add headers, where I could enable cors like this:
allowHeaders = {
"Access-Control-Allow-Origin": "*", // Required for CORS support to work
"Access-Control-Allow-Credentials": true, // Required for cookies, authorization headers with HTTPS
"Access-Control-Allow-Headers": "Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale",
"Access-Control-Allow-Methods": "POST, OPTIONS"
}
Here is what my doPost request returns:
ContentService.createTextOutput(JSON.stringify(
{
data: isAuthenticated.data,
error: true,
//request: request,
msg: query.apiKey,
//paramters:request.parameters
})).setMimeType(ContentService.MimeType.JSON)
Here is my python script to get the post response:
requests.post("https://script.google.com/macros/s/AKfycbz7kTROol8u509M_p9pMZ9XRnL-myVjcRQKeb9Etp_OIMPnH640vHf_0Jp2dvvrbto7kOg/exec",
json = requestObject)
And here is my Flutter function:
Future<http.Response> createAlbum() async{
print("Trying to make a post request");
var result = await http.post(Uri.parse('https://script.google.com/macros/s/AKfycbz7kTROol8u509M_p9pMZ9XRnL-myVjcRQKeb9Etp_OIMPnH640vHf_0Jp2dvRIco7kOg/exec'),
headers: {"Content-Type": "application/json"},
body: jsonEncode(<String, dynamic>{
"apiKey":apiKey,
"operationType":"register_user",
"operationData": {
"email": "shivam#yoptima.com",
"otp": 318728
}
}),
);
print("Here is the result: " + result.body);
}
Just to clarify things:
Get Request works for both the platforms.
Post Request works with python for AppScript.
Post Request works for any other public API from flutter.
Post Request doesn't work for Flutter when Hitting AppScript API.
I suspect it to be something to do with CORS. (But not very sure).
Flutter http library makes request via XMLHttpRequest.

I can't resolve error with API POST function

I am trying to post data via an API interface.
I have checked the JSON of the data with JSON formatter and tested the API post in ReqBin and they work fine but when I execute it in App Script I get the same error, seemingly ignoring the attributes I put in the options variable.
Error is
{"code":"not_acceptable","message":"I can only talk JSON. Please set 'Accept' and 'Content-Type' to 'application/json' in your http request header."}
Note: I have tried sending just the data as the payload without json.stringify'ing it as it is formatted as JSON to start with.
In all cases it executes, but comes back 406
Is there another way to add 'Accept':"application/json" into the header??
My Code
function exportNation()
{
// Make a POST request with a JSON payload.
var data = {
"person":
{
"email":"mikenizzckelisaweiner#tv.com",
"last_name":"Bozzrovowski",
"first_name":"Edwzzard",
"tags":"Imported Data,Volunteer,Sign Request"
}
};
var options = {
"method":"POST",
"Content-Type":"application/json",
'Accept':"application/json",
'muteHttpExceptions':true,
'payload':JSON.stringify(data)
};
var response = UrlFetchApp.fetch('https://xyz.xyz.com/api/v1/people?
access_token=5604da84fXXXXXXXXXXXXXXXX42da1ea',options );
}
Any help would be greatly appreciated!
Additional HTTP headers need to be sent as a headers object.
See: https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#advanced-parameters
var options = {
"method":"POST",
"contentType":"application/json",
"headers": {'Accept':"application/json"},

Creating Google Sheets file with REST request

I'm really new to the concept of REST and I've been trying to work with Google's Sheets, Drive, and Classroom APIs. I have been able to pull classroom roster data, but I can't for the life of me figure out how to fix this issue with a parseError and Googling for hours hasn't helped.
let init = {
method: "POST",
async: true,
headers: {
Authorization: "Bearer " + token,
"Content-Type": "application/json",
},
body: {
"mimeType": "application/vnd.google-apps.spreadsheet"
},
"contentType": "application/json"
};
fetch('https://www.googleapis.com/drive/v3/files?key='+apicall, init)
.then((response) => response.json())
.then(function(data) {
console.log(data);
console.log(init);
});
The console logs are so I can view the data, this clearly isn't going to be in the final project, but every time I send the request, it throws me error 400 parseError, which Google clearly tells me is a Content-Type error, but I specified that it's JSON, so I'm a bit confused. Any help is very much appreciated!
I figured out my own answer after some tinkering around. I changed the Content-Type to application/javascript. Even though it wasn't what I was looking for, it threw an error saying to change the fetch URI. I tried, and it made a Javascript file containing nothing but [object Object]. I was confused so I changed it all back. I read up some more on JSON formatting when I came across this quote:
When you have a Javascript object, serializing JSON is very easy:
Which lead me to remember it made the empty Javascript object... ohhhh! The body information wasn't being formatted as JSON data, but rather as a Javascript array! So then I guess I should...
var bodydata = {"name": "New spreadsheet", "mimeType": "application/vnd.google-apps.spreadsheet"};
let init = {
method: "POST",
async: true,
headers: {
Authorization: "Bearer " + token,
"Content-Type": "application/json",
},
body: JSON.stringify(bodydata)
...convert the Javascript data into a JSON string!
And it worked! It was very satisfying, but I figured I'd answer my own question on here for anyone else just learning REST APIs and figuring out stuff on their own like me!

NodeJS request doesn't encode the entire form

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.

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!!