For fetch data from the internet
https://flutter.dev/docs/cookbook/networking/fetch-data
In the official docs, they guide to use factory fromJson
but when use in a large project, I realize that way is not good for extending. I propose another way and I think it’s more flexible with the response like
{
"error": true,
"data": null,
"errors": [
{
"code": 1029,
"message": "User not found!."
}
]
}
First, create base_response.dart
/*
* Developed by Nhan Cao on 10/25/19 5:09 PM.
* Last modified 10/25/19 5:09 PM.
* Copyright (c) 2019 Beesight Soft. All rights reserved.
*/
/*
{
"error": true,
"data": null,
"errors": [
{
"code": 1029,
"message": "User not found!."
}
]
}
*/
import 'dart:core';
abstract class BaseResponse<T> {
bool error;
T data;
List<BaseError> errors;
BaseResponse(Map<String, dynamic> fullJson) {
parsing(fullJson);
}
/// @nhancv 12/6/2019: Abstract json to data
T jsonToData(Map<String, dynamic> fullJson);
/// @nhancv 12/6/2019: Abstract data to json
dynamic dataToJson(T data);
/// @nhancv 12/6/2019: Parsing data to object
parsing(Map<String, dynamic> fullJson) {
error = fullJson["error"] ?? false;
data = jsonToData(fullJson);
errors = parseErrorList(fullJson);
}
/// @nhancv 12/6/2019: Parse error list from server
List<BaseError> parseErrorList(Map<String, dynamic> fullJson) {
List errors = fullJson["errors"];
return errors != null
? List<BaseError>.from(errors.map((x) => BaseError.fromJson(x)))
: <BaseError>[];
}
/// @nhancv 12/6/2019: Data to json
Map<String, dynamic> toJson() => {
"error": error,
"data": dataToJson(data),
"errors": List<dynamic>.from(errors.map((x) => x.toJson())),
};
}
class BaseError {
int code;
String message;
BaseError({
this.code,
this.message,
});
factory BaseError.fromJson(Map<String, dynamic> json) => BaseError(
code: json["code"],
message: json["message"],
);
Map<String, dynamic> toJson() => {
"code": code,
"message": message,
};
}
Ok, to deal with data response for Brand
{
"error": true,
"data": [{"name": name, "id": id}],
"errors": [
{
"code": 1029,
"message": "User not found!."
}
]
}
Create brand_response.dart
/*
* Developed by Nhan Cao on 12/6/19 2:52 PM.
* Last modified 12/6/19 11:51 AM.
* Copyright (c) 2019 Beesight Soft. All rights reserved.
*/
import 'base_response.dart';
class BrandModel {
String name;
int id;
BrandModel({this.name, this.id});
Map<String, dynamic> toJson() {
return {"name": name, "id": id};
}
}
class BrandResponse extends BaseResponse<List<BrandModel>> {
BrandResponse(Map<String, dynamic> fullJson) : super(fullJson);
@override
dynamic dataToJson(data) {
return List<dynamic>.from(data.map((x) => x.toJson()));
}
@override
List<BrandModel> jsonToData(Map<String, dynamic> fullJson) {
List dataList = fullJson["data"];
return dataList != null
? List<BrandModel>.from(dataList.map((x) => BrandModel(name: x["name"] ?? "", id: x["id"] ?? 0)))
: <BrandModel>[];
}
}
How to use the model?
# Short guide
final brandResponse = BrandResponse(json.decode(data.body));
# Full example with bflutter
final okTrigger = Bloc<bool, List<BrandModel>>();
okTrigger.logic = (input) => input.asyncMap((d) async {
mainBloc.appLoading.push(true);
return authApi.getBrands().timeout(Duration(seconds: 30));
}).asyncMap((data) async {
if (data == null) return <BrandModel>[];
mainBloc.appLoading.push(false);
if (data.statusCode != 500) {
try {
final brandResponse = BrandResponse(json.decode(data.body));
if (brandResponse.data != null) {
return brandResponse.data;
} else {
// @nhancv 10/25/2019: Parse error
if (brandResponse.error) {
final error = brandResponse.errors.first;
throw Exception(error != null
? 'Code ${error.code ?? -1} - ${error.message ?? 'Empty'}'
: 'Unknow error.');
} else {
throw Exception(data.reasonPhrase);
}
}
} catch (e) {
throw e;
}
} else {
throw Exception(data.reasonPhrase);
}
}).handleError((error) {
mainBloc.appLoading.push(false);
mainBloc.showAlertDialog(error.toString());
});
Bonus. To deal with a flexible response like
Error
{
"error": true,
"data": null,
"errors": [
{
"code": 1029,
"message": "User not found!."
}
]
}
Successful
{
"token_type": "Bearer",
"expires_in": 1295998,
"access_token": "nhancv_dep_trai",
"refresh_token": "call_nhancv_dep_trai"
}
Create a log_in_response.dart
import 'base_response.dart';
class LoginResponse extends BaseResponse {
String tokenType;
int expiresIn;
String accessToken;
String refreshToken;
LoginResponse(Map<String, dynamic> fullJson) : super(fullJson) {
tokenType= fullJson["token_type"];
expiresIn= fullJson["expires_in"];
accessToken= fullJson["access_token"];
refreshToken= fullJson["refresh_token"];
}
@override
Map<String, dynamic> toJson() {
return {
"token_type": tokenType,
"expires_in": expiresIn,
"access_token": accessToken,
"refresh_token": refreshToken,
... super.toJson()
};
}
@override
Map<String, dynamic> dataToJson(data) {
return null;
}
@override
jsonToData(Map<String, dynamic> fullJson) {
return null;
}
}
Hey this seems promising, thanks for sharing