Reputation: 17
I need to send an Object as body parameter to a Post request. My Object is being created from a nested Json and I can't get it working so far.
I've done this quite easy in JavaScript but I haven't found the way to do this in Dart/Flutter.
The "conventional" way I've done this before is as simple as:
var data = {
"email": "[email protected]",
"password": "123",
"first_name": "qweqwe",
"billing": {
"email": "[email protected]",
"phone": "321654978",
},
"shipping": {
"first_name": "qweqwe",
}
}
By using the same structure in Dart/Flutter I get below error
[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: type '_InternalLinkedHashMap' is not a subtype of type 'String' in type cast
I've tried with Map<String, dynamic>
, Map<String, String>
, using a model for my data....
If I send the same Json but without "billing"
and "shipping"
(no nested Json) it works.
Upvotes: 0
Views: 2558
Reputation: 721
I think the other answers might be (greatly) over-complicating this. Regardless of which language you're using, to send JSON to a server, you'll need to send the data as a string, with an application/json
content type. json.encode
handles nested Maps already, so you don't need to do anything special... At all:
// Replace the "..." with the rest of your data.
var data = {"email": "[email protected]", "password": "123", ...}
// `asJson` is a String.
var asJson = json.encode(data);
// Send it
var response = await client.post('example.com/...', body: asJson, headers: {'content-type', 'application/json'});
That's all you need to do. There's not really a need to make an entire User
class with fromJson
, toJson
, etc.
As for this error - Unhandled Exception: type '_InternalLinkedHashMap' is not a subtype of type 'String' in type cast
, I have no idea what the exact cause, as you didn't provide the relevant code, but it's clear that at some point, you gave Dart a Map where it was expecting a String. Like you said, you've tried Map<String, dynamic>
and Map<String, String
, but what was really necessary was a String
.
If you're not already using the Dart analyzer (usually in an IDE plugin), this is the kind of error it can easily catch.
Hope this helped!
TLDR: Call json.encode(data)
to get a String
, and then send that String
, along with an application/json
content type, to the server.
Upvotes: 2
Reputation: 2517
The sort answer if you want to upload your data
object is to convert it to a string like so:
var jsonString = json.encode(data);
// upload jsonString as body to your server.
print("Json String is " + jsonString);
Map headers = {
'Content-type' : 'application/json',
};
http.post("www.server.com/myPostEndpoint", body: jsonString, headers: headers);
Like discussed in the comments you may need to wrap the entire content in a data
property. You may try this:
var payload = {
"data": {
"email": "[email protected]",
"password": "123",
"first_name": "qweqwe",
"billing": {
"email": "[email protected]",
"phone": "321654978",
},
"shipping": {
"first_name": "qweqwe",
}
}
};
var jsonString = json.encode(payload); // upload jsonString as body to your server. print("Json String is " + jsonString);
Map headers = { 'Content-type': 'application/json', };
http.post("www.server.com/myPostEndpoint", body: jsonString, headers: headers);
tl;dr
Its always a good idea to create a Model.
So this could be your User
model:
class User {
final String email;
final String password;
final String firstName;
final Map<String, String> billing;
final Map<String, String> shipping;
User({this.email, this.password, this.firstName, this.billing, this.shipping});
static User fromJson(dynamic json) {
return User(
email: json["email"],
password: json["password"],
firstName: json["first_name"],
billing: json["billing"],
shipping: json["shipping"],
);
}
}
It has a static constructor which is handy for creating an instance of this User
from a piece of decoded json like you have.
Now you can go ahead and use this model in your code like so:
var data = {
"email": "[email protected]",
"password": "123",
"first_name": "qweqwe",
"billing": {
"email": "[email protected]",
"phone": "321654978",
},
"shipping": {
"first_name": "qweqwe",
}
};
var user = User.fromJson(data);
print("Users Email is ${user.billing["email"]}");
It would be even cleaner to also create models for both Billing
and maybe also Shipping
.
Here is a complete example which also includes the toJson()
methods to generate Json from a parsed model:
class User {
final String email;
final String password;
final String firstName;
final Billing billing;
final Shipping shipping;
User({this.email, this.password, this.firstName, this.billing, this.shipping});
static User fromJson(dynamic json) {
return User(
email: json["email"],
password: json["password"],
firstName: json["first_name"],
billing: Billing.fromJson(json["billing"]),
shipping: Shipping.fromJson(json["shipping"]),
);
}
Map<String, dynamic> toJson() => {'email': email, 'password': password, 'first_name': firstName, 'billing': billing.toJson(), 'shipping': shipping.toJson()};
}
class Billing {
final String email;
final String phone;
Billing({this.email, this.phone});
static Billing fromJson(dynamic json) {
return Billing(email: json["email"], phone: json["phone"]);
}
Map<String, dynamic> toJson() => {'email': email, 'phone': phone};
}
class Shipping {
final String name;
Shipping({
this.name,
});
static Shipping fromJson(dynamic json) {
return Shipping(
name: json["first_name"],
);
}
Map<String, dynamic> toJson() => {'name': name};
}
And this is how you could use it:
var data = {
"email": "[email protected]",
"password": "123",
"first_name": "qweqwe",
"billing": {
"email": "[email protected]",
"phone": "321654978",
},
"shipping": {
"first_name": "qweqwe",
}
};
var user = User.fromJson(data);
print("Users Email is ${user.billing.email}");
print("Shipping name is ${user.shipping.name}");
var jsonString = json.encode(user.toJson()); // upload this as body to your server.
print("Json String is " + jsonString);
Upvotes: 4
Reputation: 11
In JSON, there should be commas only between values.
var data = {
"email": "[email protected]",
"password": "123",
"first_name": "qweqwe",
"billing": {
"email": "[email protected]",
"phone": "321654978"
},
"shipping": {
"first_name": "qweqwe"
}
}
Here i removed commas at the end of the fields "phone" and "first_name".
Upvotes: 1