jboyer777
jboyer777

Reputation: 33

How do i correct this particuar instance of Converting circular structure to JSON error

The goal is to save user information to MongoDB and display a success message in the UI. The app will ultimately be a Twilio template I can use on my apps. I expected to send the user data and auth token to a "MongoUtils" class component. Then send the auth token to the middleware. Save the info to the database. And get a successful response. Instead, the auth token passed and the data was saved, but, no success message in the UI. The error message is that of the " Converting circular structure to JSON error".

The relevant code is as follows:

const { password, displayName } = model;
  const initials = displayName[0] + displayName[1];
  const avColor = `#${Math.floor(Math.random() * 16777215).toString(16)}`;
  const email = `${window.localStorage.getItem('emailForResgistrant')}`;

  return firebaseService.auth
    .signInWithEmailLink(email, window.location.href)
    .then((result) => {
      console.log('registerSliceYes check 1 --->', result.user);
      dispatch(
        createUserSettingsFirebase({
          ...result.user,
          displayName,
          email,
          initials,
          avColor,
        })
      );
      // send success message
      dispatch(
        showMessage({
          message: `Verification email sent to ${email}. Click the link to complete account`,
        })
      );

This is the relevant snippet from the UI client registration slice. I am using redux toolkit. createUserSettingsFirebase ended up being used for sending the data to MongoDB also. Currently sends to both firebase and mongo. This takes us to the userSlice:

export const createUserSettingsFirebase = (authUser) => async (dispatch, getState) => {
  console.log('userslice check 2 --->', authUser);

  // const guestUser = getState().auth.user;
  //  current user is destructured from the firebase.auth object(not a local variable)
  const { currentUser } = firebase.auth();

  console.log('register check 1 --->', currentUser);
  // console.log('register check 1.5 --->', idTokenResult);

  /**
   * Merge with current Settings
   */
  // <--- updates user profile in firebase(only basic info)
  const user = _.merge(
    {},
    {
      uid: authUser.uid,
      from: 'firebase',
      role: ['admin'],
      data: {
        displayName: authUser.displayName,
        email: authUser.email,
        initials: authUser.initials,
        avColor: authUser.avColor,
        redirectUrl: '/apps/chat',
      },
    }
  );
  currentUser.updateProfile(user.data);
  // updates user profile in firebase(only basic info) --->

  // this updates the firebase db by ultimately making a call to firebase
  const idTokenResult = await currentUser.getIdTokenResult();

  dispatch(updateUserData(user));
  dispatch(updateUserDataMongoDB(authUser, idTokenResult.token));

  return dispatch(setUserData(user));
};

Some of the notes are for my memory. The key action here is the updateUserDataMongoDB action. It is also located in the userSlice:

export const updateUserDataMongoDB = (authUser, authtoken) => async (dispatch, getState) => {
  console.log('updateUserDataMongoDB', authtoken);

  await MongoUtils.updateUserDataTwo(authUser, authtoken)
    .then((response) => {
      console.log('mongo success message');
      dispatch(showMessage({ message: 'User data saved to MongoDB' }));
    })
    .catch((error) => {
      console.log('mongo error message', error);
      dispatch(showMessage({ message: error.message }));
    });
};

And finally, the MongoUtils class component:

static updateUserDataTwo(authUser, authtoken) {
    if (!authUser) {
      return false;
    }
    return new Promise((resolve, reject) => {
      axios
        .post(
          `${process.env.REACT_APP_API}/complete-user`,
          { authUser },
          {
            headers: {
              authtoken,
            },
          }
        )
        .then((response) => {
          resolve(response.data);
        })
        .catch((error) => {
          // handle error
          console.trace('MongoDB Utility Error(updateUserDataTwo)', error);
          reject(error);
        });
    });
  }

Also, the mongoose middleware:

exports.authCheck = async (req, res, next) => {
   console.log('authcheck ---->', req.headers); //token
    try {
        const firebaseUser = await admin
            .auth()
            .verifyIdToken(req.headers.authtoken);
        
        console.log('FIREBASE USER PASSED AUTHCHECK', firebaseUser)
       req.user = firebaseUser;
        next();
    } catch (err) {
        console.log(err)
        res.status(401).json({
            err: "Invalid or expired token",
        });
    }
};

I tried different code structures in my mongo class. I managed to save to the db but no Promise resolution. The error is as follows:

react_devtools_backend.js:2540 MongoDB Utility Error(updateUserDataTwo) TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'D'
    |     property 'c' -> object with constructor 'D'
    |     property 'b' -> object with constructor 'Dc'
    --- property 'a' closes the circle
    at JSON.stringify (<anonymous>)
    at transformRequest (defaults.js:52)
    at transform (transformData.js:16)
    at Object.forEach (utils.js:247)
    at transformData (transformData.js:15)
    at dispatchRequest (dispatchRequest.js:30)
overrideMethod  @   react_devtools_backend.js:2540
(anonymous) @   MongoUtils.js:46
Promise.catch (async)       
(anonymous) @   MongoUtils.js:43
updateUserDataTwo   @   MongoUtils.js:30
(anonymous) @   userSlice.js:189
(anonymous) @   index.js:8
dispatch    @   redux.js:659
(anonymous) @   userSlice.js:61
await in (anonymous) (async)        
(anonymous) @   index.js:8
dispatch    @   redux.js:659
(anonymous) @   registerSlice.js:121

The app works but obviously something doesn't and I can't display the message in the UI. Thanks for your input!

Edit: This is the user logged to console... not sure if this may shed some light or not:

Im {N: Array(0), l: 'AIzaSyCHVffqdXsT1_NypdTU2F29NhOUbSG-lw0', m: '[DEFAULT]', s: 'twilio-3915f.firebaseapp.com', a: Ii, …}
$: Fn {l: false, settings: em, app: FirebaseAppImpl, a: Ii, P: Array(0), …}
Aa: "eyJhbGciOiJSUzI1NiIsImtpZCI6IjgwNTg1Zjk5MjExMmZmODgxMTEzOTlhMzY5NzU2MTc1YWExYjRjZjkiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoibG9wZXpqZXNzZTEyNzdAZ21haWwuY29tIiwiaXNzIjoiaHR0cHM6Ly9zZWN1cmV0b2tlbi5nb29nbGUuY29tL3R3aWxpby0zOTE1ZiIsImF1ZCI6InR3aWxpby0zOTE1ZiIsImF1dGhfdGltZSI6MTYzODA1MzM1MywidXNlcl9pZCI6ImtKYkxVTU9mNzJXT1hLR2lOdXkzYTNaRUVIUjIiLCJzdWIiOiJrSmJMVU1PZjcyV09YS0dpTnV5M2EzWkVFSFIyIiwiaWF0IjoxNjM4MDY0NTQxLCJleHAiOjE2MzgwNjgxNDEsImVtYWlsIjoiY2hhbXBpb25zbGFuZHNjYXBlMUBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJjaGFtcGlvbnNsYW5kc2NhcGUxQGdtYWlsLmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.cWLpobXqqjp5zq_RHRCLr78CPxyVLmlL6t-Eo7_U0R6Kgsgma8bQJp_WYZEXgKfF4wgEK4XhjSfuCy2rdreaJ70NgFdeCSQdibJiPSyY_ORMkBbR8s3ux32sWKMw9HPj1YMyu-oo2INGLbi7ttwmI9fmlNMJy3SXe-VS1j7-Eo1C4FCQ6m1m2S0O59oh2QVOjuEcqwHe9c0GwRn7Edw-0ozpeCvW0pS6Df_N79c24aFhg6XgtqVLzfgfAhRheDEO1sSCl1XvLOyeMYxcSr49YvQ0dv5a8H412q7Wohc3XV4XnPd-M-C1EQNNmHnnwJBx_dT2TEO4rmIn_pJEICp6Zw"
Ba: ƒ (f)
D: xm {c: 30000, f: 960000, h: ƒ, i: ƒ, g: ƒ, …}
N: []
Oa: ƒ (f)
P: true
Pa: ƒ (f)
S: tm {a: Im, b: Array(0), enrolledFactors: Array(0), c: ƒ}
W: [ƒ]
a: Ii {c: 'AIzaSyCHVffqdXsT1_NypdTU2F29NhOUbSG-lw0', l: 'https://securetoken.googleapis.com/v1/token', m: Ze, g: {…}, h: 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/', …}
aa: []
b: Gl {i: {…}, u: 0, D: 'twilio-3915f.firebaseapp.com', v: 'AIzaSyCHVffqdXsT1_NypdTU2F29NhOUbSG-lw0', m: '[DEFAULT]', …}
ba: ƒ ()
bc: Im {N: Array(0), l: 'AIzaSyCHVffqdXsT1_NypdTU2F29NhOUbSG-lw0', m: '[DEFAULT]', s: 'twilio-3915f.firebaseapp.com', a: Ii, …}
displayName: "[email protected]"
email: "[email protected]"
emailVerified: true
h: Am {f: Ii, a: 'AFxQ4_ov0xeye6FQ23KAFH4b4Lb-7npe34-sGKQwWZYVeX2r8p…xI5aTc1c2NUTKILj-tbExZ38iwtqLppZUgQXTqHi_zMJ8C25I', b: hg, c: 1638068141823}
ha: tn {a: 'AIzaSyCHVffqdXsT1_NypdTU2F29NhOUbSG-lw0:[DEFAULT]', b: Tk}
hb: null
i: null
isAnonymous: false
ja: Fn {l: false, settings: em, app: FirebaseAppImpl, a: Ii, P: Array(0), …}
l: "AIzaSyCHVffqdXsT1_NypdTU2F29NhOUbSG-lw0"
m: "[DEFAULT]"
metadata: Fm {a: '1638053351217', b: '1638053351217', lastSignInTime: 'Sat, 27 Nov 2021 22:49:11 GMT', creationTime: 'Sat, 27 Nov 2021 22:49:11 GMT'}
multiFactor: tm {a: Im, b: Array(0), enrolledFactors: Array(0), c: ƒ}
pa: undefined
phoneNumber: null
photoURL: null
providerData: [{…}]
qa: Fn {l: false, settings: em, app: FirebaseAppImpl, a: Ii, P: Array(0), …}
refreshToken: "AFxQ4_ov0xeye6FQ23KAFH4b4Lb-7npe34-sGKQwWZYVeX2r8p2OXV_dvhY6G1vQIZ80Y-kKUr2YmQqPDwE2kbVl-_04iweIczJotfXPXjeGGcKrpc86virbSR4Tpp4r0jxBDXjDXjhm8BLKgjMLQ805REE2-4CxfWYlQzEi9VsFziNcEczNRzL-uiiH97vR3mQgwsBMcSwLogufOyfjzhXYumwxI5aTc1c2NUTKILj-tbExZ38iwtqLppZUgQXTqHi_zMJ8C25I"
s: "twilio-3915f.firebaseapp.com"
tenantId: null
u: null
uid: "kJbLUMOf72WOXKGiNuy3a3ZEEHR2"
v: hd {src: Im, a: {…}, b: 4}
ya: false
za: null
_lat: "eyJhbGciOiJSUzI1NiIsImtpZCI6IjgwNTg1Zjk5MjExMmZmODgxMTEzOTlhMzY5NzU2MTc1YWExYjRjZjkiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoibG9wZXpqZXNzZTEyNzdAZ21haWwuY29tIiwiaXNzIjoiaHR0cHM6Ly9zZWN1cmV0b2tlbi5nb29nbGUuY29tL3R3aWxpby0zOTE1ZiIsImF1ZCI6InR3aWxpby0zOTE1ZiIsImF1dGhfdGltZSI6MTYzODA1MzM1MywidXNlcl9pZCI6ImtKYkxVTU9mNzJXT1hLR2lOdXkzYTNaRUVIUjIiLCJzdWIiOiJrSmJMVU1PZjcyV09YS0dpTnV5M2EzWkVFSFIyIiwiaWF0IjoxNjM4MDY0NTQxLCJleHAiOjE2MzgwNjgxNDEsImVtYWlsIjoiY2hhbXBpb25zbGFuZHNjYXBlMUBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJjaGFtcGlvbnNsYW5kc2NhcGUxQGdtYWlsLmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.cWLpobXqqjp5zq_RHRCLr78CPxyVLmlL6t-Eo7_U0R6Kgsgma8bQJp_WYZEXgKfF4wgEK4XhjSfuCy2rdreaJ70NgFdeCSQdibJiPSyY_ORMkBbR8s3ux32sWKMw9HPj1YMyu-oo2INGLbi7ttwmI9fmlNMJy3SXe-VS1j7-Eo1C4FCQ6m1m2S0O59oh2QVOjuEcqwHe9c0GwRn7Edw-0ozpeCvW0pS6Df_N79c24aFhg6XgtqVLzfgfAhRheDEO1sSCl1XvLOyeMYxcSr49YvQ0dv5a8H412q7Wohc3XV4XnPd-M-C1EQNNmHnnwJBx_dT2TEO4rmIn_pJEICp6Zw"
[[Prototype]]: H

Upvotes: 1

Views: 324

Answers (1)

jboyer777
jboyer777

Reputation: 33

And answered, as jfriend00 explained(not sure how to mark his comment as an answer):

export const createUserSettingsFirebase = (authUser) => async (dispatch, getState) => {
  console.log('userslice check 2 --->', authUser);

  // const guestUser = getState().auth.user;
  //  current user is destructured from the firebase.auth object(not a local variable)
  const { currentUser } = firebase.auth();

  console.log('register check 1 --->', currentUser);
  // console.log('register check 1.5 --->', idTokenResult);

  /**
   * Merge with current Settings
   */
  // <--- updates user profile in firebase(only basic info)
  const user = _.merge(
    {},
    {
      uid: authUser.uid,
      from: 'firebase',
      role: ['admin'],
      data: {
        displayName: authUser.displayName,
        email: authUser.email,
        initials: authUser.initials,
        avColor: authUser.avColor,
        redirectUrl: '/apps/chat',
      },
    }
  );
  currentUser.updateProfile(user.data);
  // updates user profile in firebase(only basic info) --->

  // this updates the firebase db by ultimately making a call to firebase
  const idTokenResult = await currentUser.getIdTokenResult();

  dispatch(updateUserData(user));
  dispatch(updateUserDataMongoDB(authUser, idTokenResult.token));

  return dispatch(setUserData(user));
};

I mistakenly sent the firebase response.user(as authuser) to the database. I instead sent the user as defined in createUserSettingsFirebase. And, magically, haha, successful promise resolution and the message in the UI.

redux-logger.es.js:659  action message/showMessage @ 19:51:52.405
redux-logger.es.js:679  prev state 
{auth: {…}, rise: {…}, i18n: {…}, chatApp: {…}}
redux-logger.es.js:687  action     
{type: 'message/showMessage', payload: {…}}
payload: {message: 'User data saved to MongoDB'}
type: "message/showMessage"
[[Prototype]]: Object

Upvotes: 1

Related Questions