6

I have a Google Cloud Function which contains multiple modules to be invoked on different paths.

I am using the serverless framework to deploy my functions, but it has the limitation of only one path per function.

I want to use multiple paths in one function just like we can in the AWS serverless framework.

Suppose a user cloud function will have two paths /user/add as well as /user/remove; both the paths should invoke the same function.

Something like this:

serverless.yml

functions:
  user:
    handler: handle
    events:
      - http: user/add
      - http: user/remove

How can I have multiple API endpoints for one GCF?

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Pranay singh
  • 135
  • 1
  • 5

5 Answers5

2

Yes, indeed there is no actual REST service backing up Google Cloud Functions. It uses out of the box HTTP triggers.

To hustle the way around, I'm using my request payload to determine which action to perform. In the body, I'm adding a key named "path".

For example, consider the Function USER.

To add a user:

{
  "path":"add",
  "body":{
    "first":"Jhon",
    "last":"Doe"
  }
}

To remove a user:

{
  "path":"remove",
  "body":{
    "first":"Jhon",
    "last":"Doe"
  }
}

If your operations are purely CRUD, you can use request.method which offers verbs like GET, POST, PUT, DELETE to determine operations.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Pranay singh
  • 135
  • 1
  • 5
2

You could use Firebase Hosting to rewriting URLs.

In your firebase.json file:

"hosting": {
    "rewrites": [
          {
            "source": "/api/v1/your/path/here",
            "function": "your_path_here"
          }
    ]
}

Keep in mind this is a workaround and it has a major drawback: you will pay for double hit. Consider this if your app has to scale.

Fabio Moggi
  • 405
  • 1
  • 4
  • 12
1

You can write your functions in different runtimes. The Node.js runtime uses the Express framework. So you can use its router to build different routes within a single function.

Add the dependency

npm install express@4.17.1

The following example is using typescript. Follow these guidelines to initiate a typescript project.

// index.ts
import { HttpFunction } from '@google-cloud/functions-framework';
import * as express from 'express';

import foo from './foo';

const app = express();
const router = express.Router();

app.use('/foo', foo)

const index: HttpFunction = (req, res) => {
  res.send('Hello from the index route...');
};
router.get('', index)
app.use('/*', router)

export const api = app
// foo.ts
import { HttpFunction } from '@google-cloud/functions-framework';
import * as express from 'express';

const router = express.Router();

const foo: HttpFunction = (req, res) => {
  res.send('Hello from the foo route...');
};

router.get('', foo)

export default router;

to deploy run:

gcloud functions deploy YOUR_NAME \
--runtime nodejs16 \
--trigger-http \
--entry-point api \
--allow-unauthenticated
W.S.
  • 1,401
  • 1
  • 7
  • 9
0

Currently, in google allows only one event definition per function is supported. For more

Jishnunand P K
  • 145
  • 1
  • 8
0

Express can be installed with npm i express, then imported and used more or less as normal to handle routing:

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

// enable CORS if desired
app.use((req, res, next) => {
  res.set("Access-Control-Allow-Origin", "*");
  next();
});

app.get("/", (req, res) => {
  res.send("hello world");
});

exports.example = app; // `example` is whatever your GCF entrypoint is

If Express isn't an option for some reason or the use case is very simple, a custom router may suffice.

If parameters or wildcards are involved, consider using route-parser. A deleted answer suggested this app as an example.

The Express request object has a few useful parameters you can take advantage of:

  • req.method which gives the HTTP verb
  • req.path which gives the path without the query string
  • req.query object of the parsed key-value query string
  • req.body the parsed JSON body

Here's a simple proof-of-concept to illustrate:

const routes = {
  GET: {
    "/": (req, res) => {
      const name = (req.query.name || "world");
      res.send(`<!DOCTYPE html>
        <html lang="en"><body><h1>
          hello ${name.replace(/[\W\s]/g, "")}
        </h1></body></html>
      `);
    },
  },
  POST: {
    "/user/add": (req, res) => { // TODO stub
      res.json({
        message: "user added", 
        user: req.body.user
      });
    },
    "/user/remove": (req, res) => { // TODO stub
      res.json({message: "user removed"});
    },
  },
};

exports.example = (req, res) => {
  if (routes[req.method] && routes[req.method][req.path]) {
    return routes[req.method][req.path](req, res);
  }

  res.status(404).send({
    error: `${req.method}: '${req.path}' not found`
  });
};

Usage:

$ curl https://us-east1-foo-1234.cloudfunctions.net/example?name=bob
<!DOCTYPE html>
      <html lang="en"><body><h1>
        hello bob
      </h1></body></html>
$ curl -X POST -H "Content-Type: application/json" --data '{"user": "bob"}' \
> https://us-east1-foo-1234.cloudfunctions.net/example/user/add
{"message":"user added","user":"bob"}

If you run into trouble with CORS and/or preflight issues, see Google Cloud Functions enable CORS?

ggorlen
  • 44,755
  • 7
  • 76
  • 106