firebase-functions: `Cannot GET null` when using an Express app in HTTP functions

It seems that when passing an expressJS app to an HTTP function we cannot hit the “root” URL of the function https://us-central1-app-name.cloudfunctions.net/functionName when we do we get the following error:

Cannot GET null

This despite setting a handler for all URLs for instance:

const functions = require('firebase-functions');
const express = require('express');
const app = express();
app.get('*', (req, res) => {
  res.send('Hello world');
});

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

Adding a trailing slash works. For instance: https://us-central1-app-name.cloudfunctions.net/functionName/ works normally.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 21
  • Comments: 56 (7 by maintainers)

Commits related to this issue

Most upvoted comments

Got this to work for me previously:

https://gist.github.com/cdock1029/9f3a58f352663ea90f8b9675412c4aea

const app = require('express')();

// define your routes, etc ...

exports.route = functions.https.onRequest((req, res) => {
	
	// https://some-firebase-app-id.cloudfunctions.net/route
	// without trailing "/" will have req.path = null, req.url = null
	// which won't match to your app.get('/', ...) route 
	
	if (!req.path) {
		
		// prepending "/" keeps query params, path params intact
		req.url = `/${req.url}`
	
	}
	
	return app(req, res)

});

@team:

  1. why not to discuss here, it is very convenient.
  2. i make sure my expressjs is very good and successfully deployed, but also “Cannot GET null”, why decrease my/our quota? it’s your firebase bug. not my/our developer, customer wrong
  3. i am very very very angry! 😠 😠 😠

I arrived here from the comment in the example-functions, getting the ‘apply’ error and using the Router object. I fixed it using @cdock1029 patch.

Hello everyone - this issue has now been fixed for all Node runtimes >= 8 - see the public https://b.corp.google.com/issues/122944969. Thanks for everyone’s patience!

@sarovin that won’t work if you have query params in the request. Scroll up and use my solution which checks path and prepends / to the url.

Here is how I’ve been getting around the issue.

Lets say the deployed function should be myfunc:


  // index.js 

  var app = require('express')();

  // Home route or main functionality
  app.get('/',function(req,res,next) {
    res.send('home or root functionality');
  });

  // Some other route
  app.get('/something',function(req,res,next) {
    res.send('something else');
  });

  // Another file with express router and routes in it
  var routes = require('./routes');
  app.use(routes);

  // This allows the cloud function to be called with or without a trailing slash
  function App(req,res) {
    if (!req.url) {
      req.url = '/';
      req.path = '/';
    }
    return app(req,res);
  }

  // Export myfunc or whatever you want to call your function
  exports.myfunc = App;

@anlexN

Why are you angry?

Did you try the workaround I provided above? You can just splint that in front of your express app and it will work as expected (until a permanent fix is applied by Google Cloud). And even after that, it will continue to work because it only addresses the issue if the issue is present.

The http triggered Google Cloud Functions aren’t providing an express app, its providing a node.js request/response endpoint. Express is used under the hood to manipulate the req/res before you get it in your function, but the service isn’t actually intended to behave like an Express.Router. We are sort of bolting that functionality on top of it.

You might notice that body parsing is already done for you as well… Again, they are providing an endpoint and the server processing the routing is using STRICT routing, thats why leaving the slash off doesn’t work.

For the Google Cloud Functions team to fix this, they will probably need to disable STRICT routing in the enclosure that actually provides us with the req/res endpoint.

In the meantime, try this pattern: https://github.com/firebase/firebase-functions/issues/27#issuecomment-451451749

Hey everybody, I just solved this problem under somebody’s help, and like to share back to everyone, the key to solve this issue perfectly is that you need to fix the req.url BEFORE express app handler is called. If your fix code inside the express app handler, it has no chance to be called when missing end / 404 error happen AFTER deployed (but it works fine when you testing locally by running firebase serve --only hosting,functions or firebase experimental:functions:shell), here the hero’s message on Firebase Slack - functions channel

Also I paste the screenshot here, make sure you can see that if not join the Firebase Slack - functions channel yet:

screen shot 2017-11-02 at 10 48 37

@JulienMalige You are welcome, and also correct. I found this link that details using a similar method with Express: https://codeburst.io/express-js-on-cloud-functions-for-firebase-86ed26f9144c See: “An Automated Solution”

It is very much what @cdock1029 shared previously. Seems req.path is not important for this, but I noticed that the example does not check if req.url IS defined, but missing the proceeding slash “/”. That seems to make a difference later in routing when a query string is included.

One other note: While the functions emulator appears to allow HTTP DELETE methods with a request body, in production, the live cloud functions do not seem to acknowledge that DELETE methods might have a request body. Even reapplying the bodyParser middleware doesn’t seem to work.

this is caused by the empty value of req.url when hitting https://us-central1-app-name.cloudfunctions.net/functionName

Having read a bit online it seems that this is not an expected value for ExpressJS nor NodeJS. req.url should at least be '/':

https://github.com/expressjs/express/issues/2281#issuecomment-70447144

but why wouldn’t you consider an empty string to be valid?

Because it’s the contract of the req.url API from Node.js. The first line of an HTTP request is in the form <method> <path> HTTP/<version><CR><LF>. req.url refers to whatever the exact string that appears in the <path> portion and GET HTTP/1.1 is a syntax error (where the <path> would resolve to an empty string). As such, we will not violate the expectation that req.url cannot be an empty string.

Basically req.url should never be an empty String. We should always have to to be '\' when requesting https://us-central1-app-name.cloudfunctions.net/functionName

And while we are at it, baseUrl and originalUrl should probably be ‘/functionName’ instead of ‘’

Original report for reference: https://github.com/firebase/functions-samples/issues/101