Swift 2 - POST requests don't get parameters added - json

Following up to a question someone asked on the Alamofire github issues that never got answered because I want the answer as well.
Doing a simple request with GET adds my parameters nicely, but doing a
POST doesn't.
let parameters = ["foo": "bar"]
Alamofire.request(.POST, "url", parameters: parameters)
.responseJSON { request, response, json, error in
print("request: \(request)")
}
returns
request: Optional(<NSMutableURLRequest: 0x7f9864109cb0> { URL: https://api.github.com/repos/BasThomas/junk/issues })
while
let parameters = ["foo": "bar"]
Alamofire.request(.GET, "url", parameters: parameters)
.responseJSON { request, response, json, error in
print("request: \(request)")
}
returns
request: Optional(<NSMutableURLRequest: 0x7f9ef07ef0f0> { URL: https://api.github.com/repos/BasThomas/junk/issues?foo=bar })

The parameters of a POST are added to the request body, not to the URL. This is due to the common conventions between GET and POST.
Custom Parameter Encoding
If you need to append them to the URL (sounds like you do), then I'd suggest you take a look at the .Custom ParameterEncoding type. That will allow you to follow the same logic as the encode method, but append the parameters however you like.
Also, the methods inside the ParameterEncoding enum have now all been made public so you'll have access to the query parameter splitting and escaping.

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.

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.

how to resolve http code 412 and 200 when I am posting json using swift?

I am trying to send a very simple dictionary to the json file in my local host using swift (Alamofire)
Here is what I've done :
let parameters: Parameters = ["name" : "Danial"]
Alamofire.request("http://localhost/testing.json", method: HTTPMethod.post, parameters: parameters).response { result in
if result.response?.statusCode != nil {
if let status = (result.response?.statusCode)! as? Int {
print("status : \(status)")
}
}
}
and inside my testing.json I have the following :
{
"x":"y"
}
and I get the the http status 412 (frequently) and the 200 (without in apperance of the new json in the json file) rarely . I am very new to this networking stuff . thus , please dont attack my question as if I must know this simple thing . This has already taken me 2 days to resolve yet i am here :|
by the way there should be no error in connection as my get protocol seems to be working fine
OK, here are a couple of things I see.
When you send a POST to a server, the URL must be to a Web Service or a web app of some kind. Here it appears you are trying to POST to a resource file. Static resource files will not update automatically.
You didn't specify the encoding, so you didn't post JSON (application/json), you posted Form URL Encoded (application/x-www-form-urlencoded). Instead of being { "name": "Danial" }, you sent name=Danial.
You need to set the encoding to JSON.
let parameters: Parameters = ["name" : "Danial"]
Alamofire.request("http://localhost/testing.json",
method: HTTPMethod.post,
parameters: parameters,
encoding: JSONEncoding.default).response { result in
if result.response?.statusCode != nil {
if let status = (result.response?.statusCode)! as? Int {
print("status : \(status)")
}
}
}

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