Nzadibe
Nzadibe

Reputation: 638

How to Map Model Class from JSON Response Flutter/MongoDB

I have used Node/MongoDB for my back end and everything works fine wrt requests and responses.

For my front end, I am building a mobile app with flutter and therefore have to create model classes to represent my response. Sample response:

{success: true, message: Logged in Successfully, user: {_id: 6028965c16056b37eca50076, username: spideyr, email: [email protected], password: $2b$10$R4kYBA3Ezk7z2EBIY3dfk.6Qy.IXQuXJocKVS5PCzLf4fXYckUMju, phone: 89066060484, __v: 0}, accessToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2MTM1NDg3ODIsImV4cCI6MTYxNjE0MDc4MiwiYXVkIjoiNjAyODk2NWMxNjA1NmIzN2VjYTUwMDc2IiwiaXNzIjoicGlja3VycGFnZS5jb20ifQ.DX8-WGRkCQ9geAaQASOIzoPGpvpjdI7aV0C5o1i5Thw, refreshToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2MTM1NDg3ODIsImV4cCI6MTY0NTEwNjM4MiwiYXVkIjoiNjAyODk2NWMxNjA1NmIzN2VjYTUwMDc2IiwiaXNzIjoicGlja3VycGFnZS5jb20ifQ.RkVCGK9FfU0rxs2qf5QtJsyFaGShsL05CI320GsmAwg}

In this response body, I am only interested in the user field and therefore have created my POJO/PODO class like below:

class UserModel {

 final String id;
 final String username;
 final String email;
 final String phone;

  const UserModel({
    this.id,
     @required this.email,
     @required this.username,
     @required this.phone,
  });

  UserModel copyWith({String id, String username, String email, String phone}){
    if (
       (id == null) || identical(id, this.id) &&
       (username == null) || identical(id, this.username) &&
       (email == null || identical(email, this.email)) &&
       (phone == null || identical(phone, this.phone))) {
       return this;
    }

    return new UserModel(
       id: id ?? this.id,
       username: username ?? this.username,
       email: email ?? this.email,
       phone: phone ?? this.phone,
    );
 }

 static const empty = UserModel(email: '', username: null, phone: null, id: '');

 @override
 String toString() {
   return 'User{id: $id, username: $username, email: $email, phone: $phone}';
 }

 factory UserModel.fromMap(Map<String, dynamic> map){
    return new UserModel(
       id:map['_id'], // unable to understand why it shows error here
       username:map['username'],
       email:map['email'],
       phone:map['phone'],
    );
  }

  Map<String, dynamic> toMap(){
    return {
      'id': id,
       'username': username,
       'email': email,
       'phone': phone,
      };
    }

}

I am able to login and register a user but this error keeps appearing regarding my mapping from mongo db's _id to id in my model class UserModel.fromJSON() method. Here's the error:

I/flutter (19353): NoSuchMethodError: The method '[]' was called on null.
I/flutter (19353): Receiver: null
I/flutter (19353): Tried calling: []("_id")

Does anyone know what changes I need to make in my UserModel class? Thanks.

Upvotes: 0

Views: 786

Answers (3)

YoBo
YoBo

Reputation: 2539

The problem is in the UserResponseModel class. You are assigning Map to user.

Try this:

factory UserResponseModel.fromJSON(Map<String, dynamic> json) {
    return UserResponseModel(
      user: UserModel.fromJSON(json['user']),
      success: json['success'],
      message: json['message'],
      accessToken: json['accessToken'],
      refreshToken: json['refreshToken'],
    );
  }

Upvotes: 1

Nzadibe
Nzadibe

Reputation: 638

thanks to everyone that tried to help me understand the issue. I was missing a return statement in my APIClient class and that ensured that all the values in my map in fromJSON method were null.

Here's the correction:

class APIClient {

dynamic post(String pathSegment, Map<String, dynamic> body) async {
  Dio dio = Dio();
  Response response = await dio.post(
    '${APIConstants.BASE_URL}${APIConstants.AUTH_URL}/$pathSegment',
    data: body
  );
  if(response.statusCode == 200) {
    print(response.data);
    return response.data; // here's the change
  } else {
     print(response.statusMessage);
     throw Exception(response.statusMessage);
    }
  }
}

Upvotes: 1

Priyesh
Priyesh

Reputation: 1313

I converted your JSON to class

class Model {
    Model({
        this.success,
        this.message,
        this.user,
        this.accessToken,
        this.refreshToken,
    });

    bool success;
    String message;
    User user;
    String accessToken;
    String refreshToken;

    factory Model.fromJson(Map<String, dynamic> json) => Model(
        success: json["success"],
        message: json["message"],
        user: User.fromJson(json["user"]),
        accessToken: json["accessToken"],
        refreshToken: json["refreshToken"],
    );

    Map<String, dynamic> toJson() => {
        "success": success,
        "message": message,
        "user": user.toJson(),
        "accessToken": accessToken,
        "refreshToken": refreshToken,
    };
}

class User {
    User({
        this.id,
        this.username,
        this.email,
        this.password,
        this.phone,
        this.v,
    });

    String id;
    String username;
    String email;
    String password;
    String phone;
    int v;

    factory User.fromJson(Map<String, dynamic> json) => User(
        id: json["_id"],
        username: json["username"],
        email: json["email"],
        password: json["password"],
        phone: json["phone"],
        v: json["__v"],
    );

    Map<String, dynamic> toJson() => {
        "_id": id,
        "username": username,
        "email": email,
        "password": password,
        "phone": phone,
        "__v": v,
    };
}

Upvotes: 2

Related Questions