Reputation: 57
I'm trying to send a nested Json as body in one of the http post request from the flutter app I had been working on.
{
"user" : {
"UserName": "username",
"password":"password",
"Name": "name",
"Email": "email"
}
}
I tried many methods that were available online to do it, but every time I'm getting a 500 error. Below is a class to convert it into Json.
class SignupJson {
String username;
String email;
String name;
String password;
SignupJson(this.email, this.name, this.password, this.username);
Map toJson() =>{"user":{
'UserName': username,
'Name': name,
'password': password,
'Email': email
}};
}
And pass on it to this for a post request. (I've put an arbitrary url link)
Future<int> attemptSignup ({String username, String password, String name, String email}) async {
SignupJson data = SignupJson(username: username, password: password, name: name, email: email);
var url = 'url';
String body = jsonEncode(json);
var res = await http.post(url,
body: body);
return res.statusCode;
}
Upvotes: 4
Views: 6375
Reputation: 111
What worked for me is you have to set the Content-Type: application/json and also encode the request body using jsonEncode();
final Map<String, String> requestHeaders = {
"Authorization": "Bearer $token",
"Accept": "application/json",
"Content-Type": "application/json"
};
final reqBody = {
"action": "Wallet.GetWalletConversionSummary",
"data": {
"source_currency": data["source_currency"],
"destination_currency": data["destination_currency"],
"amount": data["amount"]
},
};
final response = await requestTypeCallMap[data["request_type"]]!(uri,
headers: requestHeaders, body: jsonEncode(reqBody));
print(jsonDecode(response.body));
Upvotes: 0
Reputation: 25
Since this is as yet unanswered, I'll take a stab. I've spent the same time as others troubleshooting against this issue and it's very frustrating.
What I learned is that the point of the content-type header is that it changes how Client.post structures the body as is creates the request, in addition to informing the server what type of data to expect. In my case, I had it erroneously set to 'application/x-www-form-urlencoded' which was working for other routes that I was passing individual maps of single-level objects and classes to, but it was failing on anything that had a key which had an object attached.
If I tried to pass a map on the key, it earned:
Expected a value of type 'String', but got one of type 'IdentityMap<String, dynamic>'.
and when I set the header properly but passed a map instead of a json.encode'ed map, I got:
Bad state: Cannot set the body fields of a Request with content-type "application/json".
From the Dart documentation for the post function:
Sends an HTTP POST request with the given headers and body to the given URL.
body sets the body of the request. It can be a String, a List or a Map<String, String>. If it's a String, it's encoded using encoding and used as the body of the request. The content-type of the request will default to "text/plain".
If body is a List, it's used as a list of bytes for the body of the request.
If body is a Map, it's encoded as form fields using encoding. The content-type of the request will be set to "application/x-www-form-urlencoded"; this cannot be overridden.
So we can see that if the specific header for content-type is missing OR if the content-type is set to application/json AND a map is passed to the body, the map will cause the post function to override the content-type header and set the header to urlencoded.
So even if the server is not expecting the content-type header, so to speak, it is expecting JSON-encoded data, and the only way to achieve that is to both:
Upvotes: 0
Reputation: 757
I code according to this json:
{
"user": {
"UserName": "username",
"password": "password",
"Name": "name",
"Email": "email"
}
}
Your Post Api call be like:
Future<User> postUser(String username, String password, String name, String
email) async {
Paste your api url here
String url = '';
final response = await http.post(apiUrl, headers: {
// Enter your headers parameter if needed
// E.g:
'Authorization' : 'xyz',
'Content-Type' : 'application/json'
},
body: jsonEncode(<String, String>{
'UserName' : username,
'password' : password,
'Name' : name,
'Email' : email
}));
if (response.statusCode == 200) {
var data = jsonDecode(response.body.toString());
print(data);
return User.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to post user.');
}
}
Your model be like:
class User {
User? user;
User({this.user});
User.fromJson(Map<String, dynamic> json) {
user = json['user'] != null ? new User.fromJson(json['user']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.user != null) {
data['user'] = this.user!.toJson();
}
return data;
}
}
class User {
String? userName;
String? password;
String? name;
String? email;
User({this.userName, this.password, this.name, this.email});
User.fromJson(Map<String, dynamic> json) {
userName = json['UserName'];
password = json['password'];
name = json['Name'];
email = json['Email'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['UserName'] = this.userName;
data['password'] = this.password;
data['Name'] = this.name;
data['Email'] = this.email;
return data;
}
}
Upvotes: 0
Reputation: 2633
I have been stuck in this issue for last 2days. Below is the way how I overcome from my problem
Future<int> attemptSignup ({String username, String password, String name, String email}) async {
SignupJson data = SignupJson(username: username, password: password, name: name, email: email);
var url = 'url';
String body = jsonEncode(data);
//here jsonEncode(data) return String bt in http body you are passing Map value
//So you have to convert String to Map
Map bodyMap = jsonDecode(body);
// your nested json data
var bodyData = { // where var store <String, dynamic> data as your demand
"user" : bodyMap
};
var res = await http.post(url,
body: bodyData,
headers: {"Content-Type": "application/json",},
);
return res.statusCode;
}
make sure to add header in http
Upvotes: 0
Reputation: 14205
Define map as <String, dynamic>
e.g. :
Map<String, dynamic> data = {
"User": {
"UserName":"username",
"Password":"password"
}
};
and add the following to the headers :
HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
request.headers.set('Accept', 'application/json');
request.headers.set('Content-type', 'application/json');
request.add(utf8.encode(json.encode(data)));
HttpClientResponse response = await request.close();
String reply = await utf8.decoder.bind(response).join();
httpClient.close();
Upvotes: 0
Reputation: 459
Add header like this:
Map<String, String> headers = {HttpHeaders.contentTypeHeader: "application/json"};
then in post request:
var res = await http.post(url, headers: headers, body: body);
Upvotes: 2