0

Dealing with a google cloud function that receives and responds as expected when there are no errors, however IF the function throws an error, on the client-side (Chrome) I receive a CORS error. I can't figure out if the issue is with how I am handling CORS or if it is because of a misuse of throw new function.https.httpsError.

Unsure if its related, the thrown error appears to be thrown AFTER the execution of the function finishes (based on logs).

  • I have set the function to be available to allUsers in the console.
  • I am using the cloud console to edit the function.
  • I did try using cors package

cloud function:

/**
 * Responds to any HTTP request.
 *
 * @param {!express:Request} req HTTP request context.
 * @param {!express:Response} res HTTP response context.
 */
const { initializeApp } = require('firebase-admin/app');
const { getFirestore, Timestamp, FieldValue } = require('firebase-admin/firestore');
const { getAuth } = require('firebase-admin/auth');
const functions = require('firebase-functions');
const app = initializeApp();
const db = getFirestore();

exports.registerUser = (req, res) => {
    let registerDetails = req.body.data;
    res.set('Access-Control-Allow-Origin', '*');
    if (req.method === 'OPTIONS') {
    // Send response to OPTIONS requests
      res.set('Access-Control-Allow-Methods', 'GET, POST')
      res.set('Access-Control-Allow-Headers', 'Content-Type, Accept')
      res.set('Access-Control-Max-Age', '3600')
      return res.status(204).send('')
    }

  return getAuth().createUser({
      email: registerDetails.Email,
      emailVerified: false,
      password: registerDetails.Password,
      displayName: registerDetails.DisplayName,
      disabled: false,
    }).then((user)=>{
      const message = 'Registered user ' + registerDetails.DisplayName + '.'
      console.log('Successfully created new user:', user.uid)
      return res.status(200).json({data: message })
//ALL OF THIS PART WORKS JUST FINE
    }).catch((error)=>{
      console.log('Error creating new user:', error.errorInfo.message)
      throw new functions.https.HttpsError("already-exists", error.errorInfo.message)
    //IF AN ERROR HAPPENS I SEE A CORS ERROR CLIENT SIDE
    })
  
};

Client Side Code:

const regUser = fbf.httpsCallable('RegisterUser');

regUser({
        FirstName: $('#registerFirstName').val(),
        LastName: $('#registerLastName').val(),
        DisplayName: $('#publicName').val(),
        Email: $('#regEmail').val(),
        Password: $('#regPassword').val()
      }).then((result)=>{
          $('#regInputHide').hide();
          $('#regResponse').show();
          $('#submitNewReg').hide();
          $('#regFuncResponse').text(result.data)   
          console.log(result.data)
      }).catch((err)=>{
        console.warn(err)
        //THIS WILL LOG "Error: internal
       //                           @ etc."
       //IN ADDITION TO THE CORS ERROR
      })
sychordCoder
  • 230
  • 3
  • 14
  • Exactly what _"CORS error"_ do you receive? – Phil Aug 09 '22 at 02:32
  • ```Access to fetch at 'https://us-central1-whiteelephant-c522f.cloudfunctions.net/RegisterUser' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.``` – sychordCoder Aug 09 '22 at 02:36
  • I'm guessing here but I suspect throwing an error bypasses the `res` object you've configured with response headers. Try `res.status(500).send(error.errorInfo.message)` instead – Phil Aug 09 '22 at 02:38
  • Yep, that works, but the problem is that on the client-side I can't see the error message. All I see is the Error: internal. The firebase docs showed you had to use the throw method to send the message to the client. That's where i'm stuck. – sychordCoder Aug 09 '22 at 02:45
  • @Phil here's my other question approaching my issue from another angle: https://stackoverflow.com/questions/73278865/google-cloud-function-not-returning-error-message – sychordCoder Aug 09 '22 at 02:51
  • 3
    You are mixing the APIs for a [HTTP Event Cloud Function](https://firebase.google.com/docs/functions/http-events) with a [Callable Cloud Function](https://firebase.google.com/docs/functions/callable). You need to use one or the other or at least add in the code to format the response from your function in a way that `httpsCallable` can parse. – samthecodingman Aug 09 '22 at 04:03
  • @samthecodingman That was most definitely it. I see now that when I created the function using the cloud console it defaulted to the HTTP rather that Callable. THANK YOU! – sychordCoder Aug 09 '22 at 04:28
  • 1
    Does @samthecodingman resolve your issue? if yes, kindly post it as an answer so anyone that is having the same issue can benefit from it. Thanks – Chanpols Aug 10 '22 at 02:01
  • 1
    @ChristianPaulAndaya Good point. Was on my phone on lunch when I made the comment, so I have now expanded it to a proper answer. – samthecodingman Aug 10 '22 at 02:18

1 Answers1

2

You are mixing the APIs for a HTTP Event Cloud Function with a Callable Cloud Function.

You need to use one or the other or at least add in the code to format the response from your function in a way that httpsCallable can parse.

// Exporting/using a `(req: Request, res: Response) => any` function is a
// HTTP Event Cloud Function pattern
exports.registerUser = (req, res) => {  
/* ... */
  // Returning a Promise chain is a Callable Cloud Function pattern
  return getAuth().createUser({
/* ... */
      // sending a response is a HTTP Event Cloud Function pattern
      return res.status(200).json({data: message })
/* ... */
      // throwing HttpsError instances is a Callable Cloud Function pattern
      throw new functions.https.HttpsError("already-exists", error.errorInfo.message)
/* ... */
}
samthecodingman
  • 23,122
  • 4
  • 30
  • 54