Home > database >  type 'Null' is not a subtype of type 'String' while trying to connect Flutter ap
type 'Null' is not a subtype of type 'String' while trying to connect Flutter ap

Time:10-30

I want to write a simple registration function and this is my code:

auth_screen.dart:

  Future<void> _submit() async {
    if (!_formKey.currentState!.validate()) {
      // Invalid!
      return;
    }
    _formKey.currentState!.save();
    setState(() {
      _isLoading = true;
    });
    try {
      if (_authMode == AuthMode.Login) {
        // Log user in
        await Provider.of<Auth>(context, listen: false).login(
          _authData['email'] as String,
          _authData['password'] as String,
        );
      } else {
        // Sign user up
        await Provider.of<Auth>(context, listen: false).signup(
          _authData['email'] as String,
          _authData['password'] as String,
          
        );
      }
    } on HttpException catch (error) {
      var errorMessage = 'Authentication failed';
      print("this is the auth data");
      print(_authData);
      if (error.toString().contains('EMAIL_EXISTS')) {
        errorMessage = 'This email address is already in use.';
      } else if (error.toString().contains('INVALID_EMAIL')) {
        errorMessage = 'This is not a valid email address';
      } else if (error.toString().contains('WEAK_PASSWORD')) {
        errorMessage = 'This password is too weak.';
      } else if (error.toString().contains('EMAIL_NOT_FOUND')) {
        errorMessage = 'Could not find a user with that email.';
      } else if (error.toString().contains('INVALID_PASSWORD')) {
        errorMessage = 'Invalid password.';
      }
      _showErrorDialog(errorMessage);
    } catch (error) {
      var errorMessage = 'Could not authenticate you. Please try again later.'  
          error.toString();
      _showErrorDialog(errorMessage);
    }

    setState(() {
      _isLoading = false;
    });
  }

auth.dart:


  Future<void> signup(String email, String password) async {
    return _authenticate(email, password, 'register');
  }

  Future<void> _authenticate(
      String email, String password, String urlSegment) async {

    final url = Uri.parse('http://10.0.2.2:8000/api/$urlSegment');
    // final url = Uri.http('http://localhost:8000/api/', 'urlSegment');
    try {
      final response = await http.post(
        url,
        body: json.encode(
          {
            'email': email,
            'password': password,

            //'returnSecureToken': true,
          },
        ),
      );
      final responseData = json.decode(response.body);
      if (responseData['error'] != null) {
        throw HttpException(responseData['error']['message']);
      }
      _token = responseData['idToken'];
      _userId = responseData['localId'];
      _expiryDate = DateTime.now().add(
        Duration(
          seconds: int.parse(
            responseData['expiresIn'],
          ),
        ),
      );
      _autoLogout();
      notifyListeners();
      final prefs = await SharedPreferences.getInstance();
      final userData = json.encode(
        {
          'token': _token,
          'userId': _userId,
          'expiryDate': _expiryDate!.toIso8601String(),
        },
      );
      prefs.setString('userData', userData);
    } catch (error) {
      throw error;
    }
  }

This is the backend(Deno) part of the project:

auth_controller.ts:

async register(ctx: RouterContext) {
    const { email, password } = await ctx.request.body().value;
    let user = await User.findOne({ email });
    if (user) {
        ctx.response.status = 422;
        ctx.response.body = { message: "Email is already exist" };
        return;
    }
    const hashedPassword = hashSync(password);
    user = new User({ email, password: hashedPassword });
    await user.save();
    ctx.response.status = 201;
    ctx.response.body = {
        id: user.id,
        name: user.name,
        email: user.email
    };
}

And this is the user.ts class:


export default class User extends BaseModel {
    public id: string = "";
    public name: string = "";
    public email: string = "";
    public password: string = "";
    constructor({ id = "", name = "", email = "", password = "" }) {
        super();
        this.id = id;
        this.name = name;
        this.email = email;
        this.password = password;
    }
    static async findOne(params: object): Promise<User | null> {
        const user = await userCollection.findOne(params);
        if (!user) {
            return null;
        }
        return new User(User.prepare(user));
    }
    async save() {
        const _id = await userCollection.insertOne(this);
        this.id = _id;
        return this;
    }
}

I get this error message when I want to test the application on Android emulator:

type 'Null' is not a subtype of type 'String'

EDIT: When I try the backend server using Postman and send post request to http://0.0.0.0:8000/api/register address. I get correct response and it works, but I don't know why do I get Null response using the Flutter app?

EDIT2: I found that the problem is in this line of the code:

const { email, password } = await ctx.request.body().value;

I can not print the email and password values and seems they are Null variables! But I don't know why as they work good with Postman!

CodePudding user response:

probably you got a null value in your map in this part since map return a null value when can't find a key, check if the Map value is not null

    try {
      if (_authMode == AuthMode.Login) {
        // Log user in
        await Provider.of<Auth>(context, listen: false).login(
          _authData['email'] as String,  // can return a null value
          _authData['password'] as String,   // can return a null value
        );
      } else {
        // Sign user up
        await Provider.of<Auth>(context, listen: false).signup(
          _authData['email'] as String,   // can return a null value
          _authData['password'] as String,   // can return a null value
          
        );
      }
    }

CodePudding user response:

Seems you're getting a null as a response value instead of a String.

EDIT:

 Future<void> signup(String email, String password) async {
    return _authenticate(email, password, 'register');
  }

Check email and password are not null. And getting the correct values.

  • Related