Search code examples
flutterdartflutter-providerdio

_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String' when connecting to API


I'm trying to do a login to my RESTAPI with node.js. But it gives me an error saying:

[ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'

I'm using Provider as my state management solution. Registering the user is going perfectly but there is something wrong with the login function.

class AuthProvider extends ChangeNotifier {
  Status _status = Status.Uninitialized;
  String _token;
  NotificationText _notification;

  Dio dio = Dio();

  Status get status => _status;
  String get token => _token;

  final String api = "https://gentle-thicket-78744.herokuapp.com/api/auth/";

  initAuthProvider() async {
    getToken().then((value) {
      String token = value;
      if (token != null) {
        _token = token;
        _status = Status.Authenticated;
      } else {
        _status = Status.Unauthenticated;
      }
      notifyListeners();
    });
  }

  //Login user
  Future<bool> login(var email, var password) async {
    _status = Status.Authenticating;
    _notification = null;
    notifyListeners();

    final url = "$api/login";

    var body = {
      'email': email,
      'password': password,
    };

    final response = await dio.post(url, data: body);
    print(response.statusCode);
    if (response.statusCode == 200) {
      print("Hello");
      var apiResponse = json.decode(response.data);
      print(apiResponse);
      print("SEcond");

       _status = Status.Authenticated;

      _token = apiResponse['token']; 
 
      await storeUserData(apiResponse);
      notifyListeners();
      return true;
    }
    if (response.statusCode == 401 || response.statusCode == 400) {
      _status = Status.Unauthenticated;
      // Alert dialog
      _notification = NotificationText('Invalid email or password.');
      notifyListeners();
      return false;
    }
    _status = Status.Unauthenticated;
    _notification = NotificationText('Server error.');
    notifyListeners();
    return false; 
    }

  Future<Map> register(String name, int budget, String currency, String email,
      String password, String confirmPassword) async {
    final url = "$api/register";

    Map<String, dynamic> body = {
      'name': name,
      'budget': budget,
      'currency': currency,
      'email': email,
      'password': password,
      'confirmPassword': confirmPassword,
    };

    Map<String, dynamic> result = {
      "success": false,
      "message": 'Unknown error.'
    };

    final response = await dio.post(
      url,
      data: body,
    );

    if (response.statusCode == 201) {
      notifyListeners();
      result['success'] = true;
      return result;
    }
    Map apiResponse = json.decode(response.data);

    if (response.statusCode == 422) {
      if (apiResponse['errors'].containsKey('email')) {
        result['message'] = apiResponse['errors']['email'][0];
        return result;
      }

      if (apiResponse['errors'].containsKey('password')) {
        result['message'] = apiResponse['errors']['password'][0];
        return result;
      }

      return result;
    }

    return result;
  }



  storeUserData(apiResponse) async {
    SharedPreferences storage = await SharedPreferences.getInstance();
    await storage.setString('token', apiResponse['token']);
    await storage.setString('name', apiResponse['name']);
  }

  Future<String> getToken() async {
    SharedPreferences storage = await SharedPreferences.getInstance();
    String token = storage.getString('token');
    return token;
  }

I have tried multiple ways to fix that but with no luck, please help.


Solution

  • dio returns the response.data already as a Map, therefore:

    Map apiResponse = response.data; // instead of: var apiResponse = json.decode(response.data);