I want convert my response API to model repository in flutter but always get error in type of model
use Dio for api request
this is my response API :
{
"success": 1,
"list": [
{
"id": "1",
"driver_id": "11081",
"company_id": "9",
"school_id": "4",
"status": 1,
"createdAt": "2022-10-14T09:22:00.000Z",
"updatedAt": "2022-10-14T09:22:03.000Z"
},
{
"id": "2",
"driver_id": "11081",
"company_id": "9",
"school_id": "5",
"status": 1,
"createdAt": "2022-10-14T20:36:47.000Z",
"updatedAt": "2022-10-14T20:36:49.000Z"
}
]
}
I try get data like this :
Future<List<ServiceEntity>> getAll() async {
final List<ServiceEntity> services = [];
try {
final response = await httpClient.post("v1/teacher/get-list");
validateResponse(response);
(response.data['list'] as List).forEach((jsonObject) {
services.add(ServiceEntity.fromJson(jsonObject));
});
} on DioError catch (e) {
exceptionHttpRequest(e);
}
return services;
}
and model is :
class ServiceEntity {
final int id;
ServiceEntity.fromJson(Map<String, dynamic> json)
: id = json['id'];
}
When i build app and debug always get this error :
I/flutter (29931):
type 'String' is not a subtype of type 'int'
I test many things but in fact did not understand what is the issue
The problem is exactly what the error says. String is not a subtype of int.
Look at the data:
The "id" is stored as a String.
Then you try pull it out in the ServiceEntitys fromJson to an int.
a. Either just store the value as an int, because that's what it is, just b like the success field.
b. or parse the string into an int.
Below an example with chatty printing to explain the type changes.
const data = {
"id": "1",
};
try{
// value stored as a String
final value = data["id"] as String;
print(value.runtimeType);
print(value);
// parse into an int
final id = int.tryParse(value);
print(id.runtimeType);
print(id);
}catch(e){
print("ERROR ${e}");
}
Your id data type is String on response, to use it as int on model class you can parse to int,
id = int.tryParse(json['id']) ?? 0;
if parser failed, it will get 0.
More about converting json and tryParse
Related
I have created a model for users details which will be returned after a post request.
Model:
class Did {
String message;
bool success;
String id;
String docHash;
String pubKey;
String privKey;
Object credential;
Did.fromJson(Map<String, dynamic> json)
: message = json["message"],
success = json["success"],
id = json["id"],
docHash = json["docHash"],
pubKey = json["pubKey"],
privKey = json["privKey"],
credential = json["credential"];
}
I'm calling the post request inside of the repository which gets called from the Bloc. The response of the post request gets parsed with my Model and than returned to the bloc. I now want to set the state to SubmissionSuccess with the data of the parsed json. This is the relevant extract of my Bloc which calls the repository:
class CreateDidBloc extends Bloc<CreateDidEvent, CreateDidState> {
final CreateDidRepository? repo;
CreateDidBloc({this.repo}) : super(CreateDidState());
#override
Stream<CreateDidState> mapEventToState(CreateDidEvent event) async* {
if (event is CreateDidFirstNameChanged) {
...
} else if (event is CreateDidSubmitted) {
yield state.copyWith(formStatus: FormSubmitting());
try {
final res = await repo?.createDid(
state.firstname,
state.lastName,
state.email,
state.phoneNumber,
state.dateOfBirth,
state.sex,
state.address,
state.city,
state.state,
state.postalCode,
state.country);
yield state.copyWith(formStatus: SubmissionSuccess(did: res));
} catch (e) {
yield state.copyWith(formStatus: SubmissionFailed(exception: e)); // e is not an exception but an Object ...why
}
}
}
}
And this is the repository which creates the post request and returns the json response as a <Did> Object. I now want to set this object as the state of the form submission when the submission is successfull.
class CreateDidRepository {
Dio dio = Dio();
Future<Did> createDid(
String firstName,
String lastName,
String email,
String phoneNumber,
DateTime? dateOfBirth,
String sex,
String address,
String city,
String state,
String postalCode,
String country) async {
var res = await dio.post("http://did-backend.herokuapp.com/create",
data: {
"firstName": firstName.trim(),
"lastName": lastName.trim(),
"email": email.trim(),
"phoneNumber": phoneNumber.trim(),
"dateOfBirth": dateOfBirth?.toIso8601String(),
"sex": sex.trim(),
"address": address.trim(),
"city": city.trim(),
"state": state.trim(),
"postalCode": postalCode.trim(),
"country": country.trim()
},
options: Options(headers: {
Headers.contentTypeHeader: "application/json",
}));
if (res.statusCode == 200) {
final json = jsonDecode(res.toString());
print(json);
return Did.fromJson(json);
}
throw "Identity request failed";
}
}
This is my form submission state (blow) but I can't seem to figure out how to set the right type of the <Did> object to accept the return value of the repository. My question is, what type do I have to define the did object to?
abstract class FormSubmissionStatus {
const FormSubmissionStatus();
}
class InitialFormStatus extends FormSubmissionStatus {
const InitialFormStatus();
}
class FormSubmitting extends FormSubmissionStatus {}
class SubmissionSuccess extends FormSubmissionStatus {
final <Did> did; //error
SubmissionSuccess({required this.did});
}
class SubmissionFailed extends FormSubmissionStatus {
final Exception exception;
SubmissionFailed({required this.exception});
}
Small extra error: The catch block inside my bloc returns an Object instead of an exception, so I can't assign that to the exception class of the SubmissionFailed state. Why does it return and Object?
Edit:
Example response of post request.
{
"id": "7hvu33b3QqWzSWVC1hmLMhLiT5PbrT8JH8JFCjPir2Ke",
"docHash": "FIJ9HZNASYIBIH9QSBSXZBSXQGRARUPGZNMAVOYPUJIXTATLSCNM9WUSLYYZWKGUVBUDLFV9UQYBA9999",
"pubKey": "GpoGnXs5S2vyMGeSxWoy7gEmyySXyrbTkX7oCcEfyuAR",
"privKey": "4MKNYQKfeqSXSV7faLSYjAY3SjysnVgHzax9LdfZYVmZ",
"credential": {
"#context": "https://www.w3.org/2018/credentials/v1",
"id": "http://example.edu/credentials/3732",
"type": [
"VerifiableCredential",
"personalInformationCredential"
],
"credentialSubject": {
"id": "did:iota:7hvu33b3QqWzSWVC1hmLMhLiT5PbrT8JH8JFCjPir2Ke",
"address": {
"street": "address",
"city": "city",
"state": "state",
"postalCode": "postalCode",
"country": "country"
},
"dateOfBirth": "dateOfBirth",
"email": "email",
"name": {
"first": "firstName",
"last": "lastName"
},
"phoneNumber": "phoneNumber",
"sex": "sex"
},
"issuer": "did:iota:A5STNhet1zgGbbnZCqniokcAdXbZZ2xcE6QWruQmctEs",
"issuanceDate": "2021-04-23T22:02:02Z",
"proof": {
"type": "MerkleKeySignature2021",
"verificationMethod": "#key-collection",
"signatureValue": "3RypuceLDTQt1Anb9WdBj7ayPS91EdiYJ6ELPMChgocm.1117tuDcgbUJddXaLoFqvAh8WWeypGnCTuPCDggJ2cMk6AVyJAjHaaCgSmgaKsGa299TxVBqfypgqbjQx1gExf2kkD9XU8ViYhZRVm9dx5qELnVxcM2H5R5YmL6rLn3RR6SbiNSc7XG.3icG5TLDkVBd8UR82LvWYgarBL6SZbFzAcDebvjkVK9wqgn1kp5LhHtp5NpzbEXeLHJzRo5GBoWihsKndffjRSDk"
}
},
"message": "You have successfully created your digital identity, firstName",
"success": true
}
please use this website to convert you'r json to dart class.
please instead of :
if (res.statusCode == 200) {
final json = jsonDecode(res.toString());
print(json);
return Did.fromJson(json);
}
use this :
if (res != null && res.statusCode == 200) {
return Did.fromJson(response.data);
}
and believe me, use different state class for different situation, here for example you use same state for progress, error and loaded.
I hope i was able to help.
So i'm trying to create a list with objects of type 'MessageListItem'. I'm trying to push data returned from my API into the list. The variable I want it pushed into is 'messages'. I am getting an error in the 'getMessages()' function.
The error I am getting is: A value of type 'MessageListItem' can't be assigned to a variable of type 'List'.
The API call & code is:
List<MessageListItem> messages;
getMessages() async {
List<MessageListItem> res = MessageListItem.fromJson(await getMessageList());
// I'm getting the error on the line above.
print(res);
}
Future<dynamic> getMessageList() async {
final response = await http.get(baseUrl + 'message/jxchumber');
print(response.statusCode);
if (response.statusCode == 200) {
var res = json.decode(response.body);
return res;
} else {
throw Exception('Failed to get data');
}
}
MessageListItem Class
class MessageListItem {
int id;
int senderId;
int recipientId;
String senderUsername;
String recipientUsername;
int itemId;
String messageContentString;
bool read;
dynamic dateTimeSent;
MessageListItem(
{this.id,
this.senderId,
this.recipientId,
this.senderUsername,
this.recipientUsername,
this.itemId,
this.messageContentString,
this.read,
this.dateTimeSent});
factory MessageListItem.fromJson(Map<String, dynamic> json) {
return MessageListItem(
id: json['id'],
senderId: json['senderId'],
recipientId: json['recipientId'],
senderUsername: json['senderUsername'],
recipientUsername: json['recipientUsername'],
itemId: json['itemId'],
messageContentString: json['messageContentString'],
read: json['read'],
dateTimeSent: json['dateTimeSent'],
);
}
}
The data being returned from the API is:
[
{
"id": 4,
"senderId": 1,
"recipientId": 3,
"senderUsername": "jxchumber",
"recipientUsername": "pavster31",
"itemId": 0,
"messageContentString": "hello1",
"read": false,
"dateTimeSent": "2020-12-14T22:23:55.1473414"
},
{
"id": 3,
"senderId": 1,
"recipientId": 9,
"senderUsername": "jxchumber",
"recipientUsername": "larsen",
"itemId": 0,
"messageContentString": "hello1",
"read": false,
"dateTimeSent": "2020-12-14T16:04:50.8232055"
}
]
I'm trying to push it into the variable 'messages'
Try this
getMessages() async {
var list = await getMessageList();
List<MessageListItem> res = list.map((i)=>MessageListItem.fromJson(i)).toList();
}
I am getting this response from the API:
[
{
"id": 1,
"company_id": 2,
"surname": "Surname",
"name": "Name",
"employee_position_id": 1,
"phone_number": "+xxx xxx xxx xxx",
"email": "mail#mail.mail",
"user_id": 1,
"contact_level": null,
"created_at": "2020-10-03T16:50:59.000000Z",
"updated_at": "2020-10-03T17:05:54.000000Z",
"deleted_at": null,
"full_name": "Surname Name",
"position_name": "IT",
"company_name": "Company One"
}
]
According to every tutorial I found, this code should work:
void _getContacts() async {
var res = await Network().getData('/contacts');
final Map<String, dynamic> body = json.decode(res.body);
// print(body.runtimeType);
}
However, it gives me this error:
E/flutter (23716): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>'
When I print the body.runtimeType it says List<dynamic>
I double checked, i tripple checked everything, json seems to be in a correct format, all the code seems to be written correctly.
How is it possible it gives me List instead of a Map? and how do I force the json.decode to give me a Map instead of a List?
There is List you have to iterate it.
if there is only one object of your list then you can use it like this
void _getContacts() async {
var res = await Network().getData('/contacts');
var response= json.decode(res.body);
final Map<String, dynamic> body = response[0];
// print(body.runtimeType);
}
if there is more than one object on your list then you can use it like this
void _getContacts() async {
var res = await Network().getData('/contacts');
var response= json.decode(res.body);
final Map<String, dynamic> body = response.map((e)=>e);
// print(body.runtimeType);
}
I want to develop a flutter app and I am finding it difficult to parse this JSON I have seen posts regarding this but I am finding it difficult to parse this. Help a beginner out! Here is the JSON link " https://api.covid19india.org/state_district_wise.json "
I am simply using:
Future getJsonDistrictData() async {
var response = await http.get(Uri.encodeFull(url1));
var converttojson1 = json.decode(response.body);
setState(() {
myData= converttojson1;
});
}
Text("${myData['Kerala']['districtData']['Thrissur']['confirmed']}")
But this would mean I have to write the same line for every district confirmed cases.
How should I proceed?
I have made the following example of an implementation you can use the parse the data from the URL in your question.
It can be simplified if you don't need the lastUpdatedTime and delta_confirmed since it looks like this is always the empty String and zero in the API.
import 'dart:convert';
class State {
final Map<String, DistrictData> districts = {};
State.fromJson(dynamic json) {
for (final district in json['districtData'].keys) {
districts[district as String] =
DistrictData.fromJson(json['districtData'][district]);
}
}
#override
String toString() => districts.toString();
}
class DistrictData {
final int confirmed;
final DateTime lastUpdatedTime;
final int delta_confirmed;
DistrictData(this.confirmed, this.lastUpdatedTime, this.delta_confirmed);
factory DistrictData.fromJson(dynamic json) => DistrictData(
json['confirmed'] as int,
(json['lastupdatedtime'].isEmpty as bool)
? null
: (DateTime.parse(json['lastupdatedtime'] as String)),
json['delta']['confirmed'] as int);
#override
String toString() =>
'{ confirmed: $confirmed, lastUpdatedTime: $lastUpdatedTime, delta_confirmed: $delta_confirmed }';
}
void main() {
final states = json.decode(input).map(
(String key, dynamic value) => MapEntry(key, State.fromJson(value)))
as Map<String, State>;
states.forEach((key, value) => print('$key : $value'));
/*
Kerala : {Thrissur: { confirmed: 13, lastUpdatedTime: null, delta_confirmed: 0 }, Alappuzha: { confirmed: 5, lastUpdatedTime: null, delta_confirmed: 0 }}
Delhi : {East Delhi: { confirmed: 1, lastUpdatedTime: null, delta_confirmed: 0 }}
*/
}
const input = '''
{
"Kerala": {
"districtData": {
"Thrissur": {
"confirmed": 13,
"lastupdatedtime": "",
"delta": {
"confirmed": 0
}
},
"Alappuzha": {
"confirmed": 5,
"lastupdatedtime": "",
"delta": {
"confirmed": 0
}
}
}
},
"Delhi": {
"districtData": {
"East Delhi": {
"confirmed": 1,
"lastupdatedtime": "",
"delta": {
"confirmed": 0
}
}
}
}
}
''';
Copy your JSON in this link(https://javiercbk.github.io/json_to_dart/) and get model Class.
Example:
For example your Model Class Name is CovidModel. As you get response from network call, pass data to you model class and get object like this:
CovidModel _covidModel = CovidModel.fromJson(response.data);
now you can use _covidModel to get inner objects and show result in app page.
How to handle the difference between the results of a successful and failed fire response?
RESPONSE SUCCESS:
{
"header":{
"status":true,
"respcode":"00",
"message":"Successfully."
},
"data":{
"userid":"3485345",
"password":"3423424",
"bit18":"0000",
}
}
RESPONSE FAILED:
{
"header":{
"status":false,
"respcode":"01",
"message":"Userid Tidak Terdaftar"
},
"data":""
}
assuming you'll always have headers in your responses, you can do something like this:
Map<String, dynamic> res1 = {
"header": {"status": true, "respcode": "00", "message": "Successfully."},
"data": {
"userid": "3485345",
"password": "3423424",
"bit18": "0000",
}
};
Map<String, dynamic> res2 = {
"header": {
"status": false,
"respcode": "01",
"message": "Userid Tidak Terdaftar"
},
"data": ""
};
// bla = res2 for failed case
final bla = res1;
if (bla['header']['status']) {
print(res1['data']['userid']);
// do your success code here
} else {
// do your fail code here
print('fail');
}
I don't know why in the failed case, data is string (and not object). In theory, the failed case should have an empty object instead of a string. Any way, assuming you don't have control over the server's response, you might want to do something like below :
(The first two lines I wrote just to make sure the parsing works.)
Map<String, dynamic> mData = {
"header":{
"status":true,
"respcode":"00",
"message":"Successfully."
},
"data":{
"userid":"3485345",
"password":"3423424",
"bit18":"0000",
}
};
String jData = json.encode(mData);
Map<String, dynamic> decodedBody = json.decode(jData);
print(decodedBody["header"]["respcode"]); // prints 00
if (decodedBody['header']['status'])
{
User user = User.fromJson(decodedBody['data']);
print(user.userId); // This prints 3485345
}
else {
// login failed
}
And the User model is defined as below :
class User {
final String userId;
final String password;
final String bit18;
User({#required this.userId, #required this.password, this.bit18});
User.fromJson(Map json)
: this.userId = json['userid'],
this.password = json['password'],
this.bit18 = json['bit18'];
}