Firebase Hosting with dynamic cloud functions rewrites
What seems to be the main issue is that this:
{
"source": "/api",
"function": "api"
}
is actually rewriting to https://my-firebase-app.cloudfunctions.net/api/api
instead of https://my-firebase-app.cloudfunctions.net/api
like you'd expect. Notice how api
is repeated.
My solution to this is to create a main
function which hosts all other top-level functions:
const functions = require('firebase-functions');
const express = require('express');
const app = express();
app.get('/users/:userId/:userData/json', (req, res) => {
// Do App stuff here
}
// A couple more app.get in the same format
// Create "main" function to host all other top-level functions
const main = express();
main.use('/api', app);
exports.main = functions.https.onRequest(main);
You can now use this main
function to delegate to all other functions without breaking your URL structure:
{
"source": "/api/**", // "**" ensures we include paths such as "/api/users/:userId"
"function": "main"
}
And voila! You can now access all api
function calls via https://my-app.firebaseapp.com/api/users/:userId/:userData
just like you'd expect.
Calling this endpoint, now rewrites to https://my-firebase-app.cloudfunctions.net/main/api
which is technically correct. You can then add more top-level functions by simply adding them to your main
function if you wish:
const hooks = express();
main.use('/hooks/, hooks);
You can use a single Firebase hosting rewrite rule with a complementing rewrite middleware in Express.
Add a rewrite in your
firebase.json
file.{ "source": "/api/**", "function": "api" }
Include an app.use() middleware to rewrite the request url.
const functions = require('firebase-functions'); const express = require('express'); const API_PREFIX = 'api'; const app = express(); // Rewrite Firebase hosting requests: /api/:path => /:path app.use((req, res, next) => { if (req.url.indexOf(`/${API_PREFIX}/`) === 0) { req.url = req.url.substring(API_PREFIX.length + 1); } next(); }); app.get('/users/:userId/:userData/json', (req, res) => { // Do App stuff here }); exports[API_PREFIX] = functions.https.onRequest(app);