Declare separate Firebase Cloud Functions and still use Express.js

Issue

There are many examples of using Express for Firebase Cloud Functions.

In every example of I have found the code exposes the Express app as a single Cloud Function:

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

For one’s Firebase Project Functions that means they will see one entry called “app” and all logs for all Express.js HTTP listeners will go to one place in Firebase. This also means, no matter how large one’s Express.js app is, Firebase will deploy a single function in production for the app.

Alternatively, when using firebase-functions.https.onRequest you get separate functions for each export, for example, in Typescript:

export const hello = functions.https.onRequest(async (req, res) => {
  res.status(200).send('hello world');
});

And in Firebase Console, I have my hello function and also another function in my index.js:

enter image description here

This also means Firebase will create different nodes/instances for each function: hello and emphemeralKey.

And I will get separate logging for each function in the Firebase Console.

I would like to use middleware to ensure that valid auth tokens are being passed to my endpoint Cloud Functions like this Firebase example but I would prefer not to use a single “app” single Cloud Function, I would prefer a dedicated function for function export in my index.js.

Solution

Thanks to Doug Stevenson for his answer and help. I wanted to provide my own answer though.

So the answer to my question is, generally speaking: no you can’t.

As Doug was pointing out, this is not a problem for many people’s scaling needs. Firebase will create up to 1,000 instances of your function to scale.

I wanted to provide a slightly different answer then Doug’s to how I would write an Express app and have different Firebase Cloud Functions for a project:

const payment = express()
const order = express()
payment.get('/route', ...)
order.get('/route', ...)
export const payment = functions.https.onRequest(payment)
export const order = functions.https.onRequest(order)

The advantage here is that I can start to express REST or RPC routes like:

  • /payment/someaction (RPC)
  • /order (get,put,post, etc.)

Another benefit is that I can provide a “test” API and a “live” API for things like credit card payments/processing:

// [START Express LIVE App]


// [START get user]
app.get('/user', async (req, res) => {
  await handleGetUser(req, res, paymentServiceLive);
});
// [END get user]

// [START claim]
app.post('/claim', async (req, res) => {
  await handleClaim(req, res, claimEmailTo);
});
// [END claim]

// [START user]
app.post('/user', async (req, res) => {
  await handleUserPost(req, res, paymentServiceLive);
});
// [END user]

// [START ephemeralKey]
app.post('/ephemeralKey', async (req, res) => {
  await handleEphemeralKey(req, res, paymentServiceLive);
});
// [END ephemeralKey]


// [START charge]
app.post('/charge', async (req, res) => {
  await handleCharge(req, res, paymentServiceLive);
});
// [END charge]

// [START purchase]
app.post('/purchase', async (req, res) => {
  await handlePurchase(req, res, paymentServiceLive);
});
// [END purchase]

//Expose Express API as a single Cloud Function:
exports.app = functions.https.onRequest(app);

// [END Express LIVE App]



// [START Express TEST App]

// [START get user]
appTest.get('/user', async (req, res) => {
  console.log('appTest /user get', req);
  await handleGetUser(req, res, paymentServiceTest);
});
// [END get user]

// [START claim]
appTest.post('/claim', async (req, res) => {
  await handleClaim(req, res, claimEmailToTest, true);
});
// [END claim]


// [START user]
appTest.post('/user', async (req, res) => {
  console.log('appTest /user post', req);
  await handleUserPost(req, res, paymentServiceTest);
});
// [END user]

// [START ephemeralKey]
appTest.post('/ephemeralKey', async (req, res) => {
  await handleEphemeralKey(req, res, paymentServiceTest)
});
// [END ephemeralKey]


// [START charge]
appTest.post('/charge', async (req, res) => {
  await handleCharge(req, res, stripeTest);
});
// [END charge]

// [START purchase]
appTest.post('/purchase', async (req, res) => {
  await handlePurchase(req, res, paymentServiceTest);
});
// [END purchase]

//Expose Express API as a single Cloud Function:np
exports.apptest = functions.https.onRequest(appTest);

// [END Express TEST App]

This allows me to have a development environment and a live environment. in my app config files I just have a different API url:

/us-central1/apptest

or

/us-central1/app

Answered By – Brian Ogden

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published