I am trying to send an HTTP PUT request to FastAPI backend from flutter code. I jsonify the data before I put into the request body. Here are my data classes:
class ListeningHistory {
final String userId;
List<BareMinPost> podcasts;
ListeningHistory({required this.userId, required this.podcasts});
Map<String, dynamic> toJson() {
podcasts = []; // for simplicity's sake
return {'user_id': userId, 'podcasts': jsonEncode(podcasts)};
}
Please note that I intentionally replaced the actual podcasts with an empty array above for the sake of simplicity for this example.
class BareMinPost {
final String title;
final String publishedDate;
final int pausedAt;
BareMinPost({
required this.title,
required this.publishedDate,
required this.pausedAt,
});
BareMinPost.fromJson(Map<String, dynamic> json)
: title = json['title'] as String,
publishedDate = json['publishedDate'] as String,
pausedAt = json['pausedAt'] as int;
Map<String, dynamic> toJson() =>
{'title': title, 'publishedDate': publishedDate, 'pausedAt': pausedAt};
@override
String toString() {
return "BareMinPost - title: $title publishedDate: $publishedDate puasedAt: $pausedAt";
}
}
I use the following piece of code to json encode the data:
import 'dart:convert';
...
ListeningHistory hist = ListeningHistory(
userId: "$userId", podcasts: previouslyListenedTo);
String reqBody = json.encode(hist);
dualLog(logger, '------------------->>>>-----$reqBody');
log line prints out as follows:
------------------->>>>-----{"user_id":"org.couchdb.users:alp","podcasts":"[]"}
Please note the double quotes around the array at the end. These, I believe should not be there but they are for some reason.
And eventually when I send this request the fastapi server, it complains as follows:
ERROR: {"detail":[{"type":"list_type","loc":["body","podcasts"],"msg":"Input should be a valid list","input":"[]"}]}
What am I missing here ?
I expanded the comment and included an example:
import 'dart:convert' show JsonUnsupportedObjectError, jsonEncode, jsonDecode;
class BareMinPost {
BareMinPost({required this.title});
final String title;
Map<String, dynamic> toJson() => {'title': title};
factory BareMinPost.fromJson(Map<String, dynamic> json) {
// Validate input
if (json
case {
'title': String title,
}) {
return BareMinPost(title: title);
} else {
throw JsonUnsupportedObjectError(json,
cause: 'BareMinPost: Json validation failed');
}
}
}
class ListeningHistory {
final String userId;
List<BareMinPost> podcasts;
ListeningHistory({required this.userId, required this.podcasts});
Map<String, dynamic> toJson() {
return {
'user_id': userId,
'podcasts': podcasts
.map(
(e) => e.toJson(),
)
.toList()
};
}
factory ListeningHistory.fromJson(Map<String, dynamic> json) {
// Validate input
if (json
case {
'user_id': String userId,
'podcasts': List podcasts,
}) {
return ListeningHistory(
userId: userId,
podcasts: podcasts.map((e) => BareMinPost.fromJson(e)).toList(),
);
} else {
throw JsonUnsupportedObjectError(json,
cause: 'ListeningHistory: Json validation failed');
}
}
}
Usage:
void main(List<String> args) {
final history = ListeningHistory(userId: 'json1997', podcasts: [
BareMinPost(title: 'Song A'),
BareMinPost(title: 'Song B'),
]);
// Encoding
print('Encoding: ...');
print(
history.toJson(),
); // Prints: {user_id: json1997, podcasts: [{title: Song A}, {title: Song B}]}
final jsonString = jsonEncode(history.toJson());
print(
jsonString,
); // Prints: {"user_id":"json1997","podcasts":[{"title":"Song A"},{"title":"Song B"}]}
// Decoding
print('\nDecoding ...');
final jsonMap = jsonDecode(jsonString);
print(jsonMap);
final historyClone = ListeningHistory.fromJson(jsonMap);
}
The console output is listed below:
Encoding: ...
{user_id: json1997, podcasts: [{title: Song A}, {title: Song B}]}
{"user_id":"json1997","podcasts":[{"title":"Song A"},{"title":"Song B"}]}
Decoding ...
{user_id: json1997, podcasts: [{title: Song A}, {title: Song B}]}