hidjou / classsed-react-firebase-functions

327 stars 180 forks source link

Value for argument "data" is not a valid Firestore document. Cannot use "undefined" as a Firestore value (found in field userId). #5

Closed alanrodriguezdotme closed 4 years ago

alanrodriguezdotme commented 5 years ago

Following along with your YouTube tutorial (which is great btw!), and I keep hitting this error when I try to create a new user.

The error happens when I try to use createUserWithEmailAndPassword(). In the .then() right after that, something in that callback is not valid according to Firestore, and data.user.userId shows up as undefined. In Postman, I get a 500 error with an empty object as an error. In the console, here's what I get:

Error: Value for argument "data" is not a valid Firestore document. Cannot use "undefined" as a Firestore value (found in field userId).
at Object.validateUserInput (C:\Users\alanro\Projects\PlayPlay2\functions\node_modules\@google-cloud\firestore\build\src\serializer.js:277:15)
at validateDocumentData (C:\Users\alanro\Projects\PlayPlay2\functions\node_modules\@google-cloud\firestore\build\src\write-batch.js:612:26)
at WriteBatch.set (C:\Users\alanro\Projects\PlayPlay2\functions\node_modules\@google-cloud\firestore\build\src\write-batch.js:232:9)
at DocumentReference.set (C:\Users\alanro\Projects\PlayPlay2\functions\node_modules\@google-cloud\firestore\build\src\reference.js:330:14)
at db.doc.get.then.then.then (C:\Users\alanro\Projects\PlayPlay2\functions\index.js:131:48)
at process._tickCallback (internal/process/next_tick.js:68:7)

Here's where I currently am with the tutorial:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const firebase = require('firebase');
const app = require('express')();

admin.initializeApp();

const firebaseConfig = {
   ...
};

firebase.initializeApp(firebaseConfig);

const db = admin.firestore();

const isEmpty = (string) => {
    if (string.trim() == '') {
        return true;
    } else {
        return false;
    }
}

const isEmail = (email) => {
    const regEx = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    if (email.match(regEx)) {
        return true;
    } else {
        return false;
    }
}

// SIGNUP ROUTE
app.post('/signup', (req, res) => {
    const newUser = {
        email: req.body.email,
        username: req.body.username,
        password: req.body.password,
        confirmPassword: req.body.confirmPassword
    }

    let errors = {};

    // check if email is not empty and is valid
    if (isEmpty(newUser.email)) {   errors.email = 'Email field must not be empty'} 
    else if (!isEmail(newUser.email)) { errors.email = 'Email must be valid' } 

    // check if other fields are empty
    if (isEmpty(newUser.password)) { errors.password = 'Password must not be empty' }
    if (newUser.password !== newUser.confirmPassword) { errors.confirmPassword = 'Passwords must match' }
    if (isEmpty(newUser.username)) { errors.username = 'Username must not be empty'}

    if (Object.keys(errors).length > 0) {
        return res.status(400).json(errors)
    }

    let token, userId;
    // TODO: validate data
    db.doc(`/users/${newUser.username}`).get()
        .then(doc => {
            console.log(newUser)

            if (doc.exists) {
                return res.status(400).json({ username: 'this username is already taken'})
            } else {
                return firebase
                    .auth()
                    .createUserWithEmailAndPassword(newUser.email, newUser.password)
            }
        })
        .then((data) => {
            console.log('data:', data)
            userId = data.user.userId
            console.log('userId:', userId)
            return data.user.getIdToken();
        })
        .then((idToken) => {
            token = idToken;
            const userCredentials = {
                username: newUser.username,
                email: newUser.email,
                createdAt: new Date().toISOString(),
                userId
            }
            return db.doc(`/users/${newUser.username}`).set(userCredentials)
        })
        .then(() => {
            return res.status(201).json({ token });
        })
        .catch((err) => {
            console.error(err);
            if(err.code === 'auth/email-already-in-use') {
                return res.status(400).json({ email: 'email is already in use'})
            } else {
                return res.status(500).json({ error: err.code });
            }
        })
})

exports.api = functions.https.onRequest(app);

Any suggestions to fix this would be a big help. Thanks!

alanrodriguezdotme commented 5 years ago

And I just fixed it. Looks like data.user.userId has been changed to data.user.uid. 🤷‍♂️

thilanka commented 4 years ago

close the issue if you found the solution