can firebase callable functions be used to build an API? - firebase

I know that the difference between firebase's cloud callable functions and http functions have been clarified here. However, I still find myself confused in terms of the specific use case of building an API for CRUD operations to the firestore.
I know how to do this with http functions and express, but http functions don't pass a context with user tokens like how callable functions does.
Can/how do you create a router similar to how one would with express with http functions (see below) that allow you to create an API that can handle GET, POST, PUT, and DELETE requests for public and private routes with middleware all within one callable function? Or would you need to create a new callable function for each "route"?
// Define Routes
app.use('/api/users', require('./routes/users'));
app.use('/api/auth', require('./routes/auth'));
app.use('/api/contacts', require('./routes/contacts'));
Can you also hook up the callable function to be called from firebase hosting on particular routes like http functions can (see below)?
"hosting": {
"public": "client/build",
"rewrites": [
{
"source": "/api{,/**}",
"function": "api"
},
{
"source": "**",
"destination": "/index.html"
}
]
},
Or would it just be better to stick with passing an express app through http functions and authenticating by just passing the user token in the request headers?

After checking this Community Answer I saw that this is not possible, as you can see:
HTTP requests to callable functions don't really come "from" a URL. They come from anywhere on the internet. It could be a web site, Android or iOS app, or someone who simply knows the protocol to call the function.
So unless you workaround that by sending the URL in the data of the callable function, it will not work. And even if you do, it just would go against the principle of callable functions, so I would recommend that you use Http Functions for that purpose.

Related

Can I view the configuration for the Firebase functions used by my website using Firebase/Google Cloud's UI?

I deployed a new version of a web app that included some new Firebase functions. The new Firebase functions were inaccessible upon deployment.
I was able to find the root cause by familiarity with Firebase's configuration: the function requests were intended to route through the main app domain, and be redirected on the Firebase server to their final destination. (This should have been set up with Firebase's 'rewrites' section of firebase.json, but wasn't.)
A partial view of my rewrites section of firebase.json:
"rewrites": [
{
"source": "/getPlaces",
"function": "getPlaces"
},
...
{
"source": "**",
"destination": "/index.html"
}
]
In plain English, this says, "Firebase server: every time you get a request routing to https://my.app/getPlaces, I want you to not route to that address within my app; I want to invoke my Cloud function instead. Otherwise, route normally."
Yet when I look at the Functions tab of my Firebase console, all I see is this:
Under 'Request', it says https://us-central1-my-app.cloudfunctions.net/getPlaces. That gives me just one of the ways to access my function; the other is https://my.app/getPlaces, as defined in rewrites. I need to know all of the addresses that Firebase will respond to, not just the default one using cloudfunctions.net.
Is it possible to see the entire configuration for the deployed Firebase functions anywhere in the web UI, ie console.firebase.com or console.cloud.google.com, where redirects from rewrites like this can be seen?

Would URL rewrite make Firebase cloud function response come from my custom domain?

Firebase documentation mention that you can serve cloud functions using a custom domain using url rewrites.
You can use rewrites to serve a function from a Firebase Hosting URL.
The following example is an excerpt from serving dynamic content using
Cloud Functions.'
"hosting": {
// ...
// Directs all requests from the page /bigben to execute the bigben function
"rewrites": [ {
"source": "/bigben",
"function": "bigben"
} ]
}
Cloud function response can return values to set in a cookie the following way:
res.cookie("session", sessionCookie, {
expires: new Date(new Date().getTime() + expiresIn), // Add 2 weeks (in milliseconds) to the current epoch
httpOnly: true,
secure: true,
sameSite: "none",
domain: req.get("host")
});
// Return an HTTP 204 NO CONTENT response
return res.sendStatus(204);
However in most of browsers, 3rd party cookies are not allowed, only 1st party.
I understand I can call the cloud function using my custom domain thanks to the url rewrite, however what about the response, will it be consider 1st party or 3rd party?
From the browser's perspective the cookie will be coming from Firebase Hosting directly, and therefore the cookie will be considered a First Party Cookie. Notice that the rewrite in order to serve the Cloud Function from the Firebase Hosting URL all happens serverside, and therefore the behavior explained.

Is it possible to cache Cloud Function invocation result in Firebase Hosting rewrite indepedently of the requested URL?

I'm rewriting multiple paths in Firebase Hosting to a Cloud Function that always returns the same result. I need to invoke the function once, cache its result, and return it for any subsequent requests to any of these paths. However, as the documentation states, the cached content is served based on:
The hostname
The path
The query string
The content of the request headers specified in the Vary header
So, if a different URL is requested, the function will be invoked again. But is there a way to avoid that? Setting the Cache-Control header does prevent the function from invoking again when the same URL is requested, but not when a different one is.
Here is my Hosting and Functions configuration:
firebase.json:
{
"hosting": {
"rewrites": [
{
"source": "**",
"function": "myFunction"
}
]
}
}
functions/index.ts:
import * as functions from "firebase-functions"
export const myFunction = functions.https.onRequest((req, res) => {
res.set("Cache-Control", "public, max-age=31536000")
res.send("This is a Cloud Function.")
})
The caching behavior of Firebase Hosting (and web browsers) is always dependent on the URL path.
There are a couple ways you could try to work around this, depending on your goals:
Use a redirect (for instance, to /) instead of the rewrite. The the cloud function can then serve content only on a known (and cacheable) path.
Serve a static page instead of a cloud function on every path, then have that static page use javascript to call your cloud function on a known, cached path. The initial static page wouldn't be cached, but it should be faster than a function.
The integration between Firebase Hosting and Cloud Functions/Cloud Run allows your (Cloud Functions/Cloud Run) code to control the content of the URL that was requested from Firebase Hosting.
You can modify other hosted files, but will have to call the Firebase Hosting API for this. For an example of this, see How to update a file that I deployed to Firebase Hosting?

Firebase uses cloudfunctions.net instead of hosting rewrites rules

I have set up rewrites for named functions in firebase.json but still firebase.functions().httpsCallable() envokes [my-server].cloudfunctions.net/[function-name] instead of [my-server].com/
I am upgrading a current project that has been working fine with cloudfunctions.net, but I would like to limit the domain names being called because of some firewalls blocking that domain.
Reading the guide if thought this addition in firebase.json would be sufficient:
"rewrites": [
{
"source": "/getResponse",
"function": "getResponse"
}]
and then calling the function from my app with:
firebase.functions().httpsCallable('getResponse')
...But that envokes [my-server].cloudfunctions.net/getResponse instead of [my-server].com/getResponse
Opening [my-server].com/getResponse in my browser works, so I figure, there is some sort of explicit setting on firebase.functions() where I can force it to use custom domain?
Thanks you for any help
There is no way to configure the Firebase client SDK for callable functions to invoke anything other than the default URL for the function. If this is somehow important to you, you are free to file a feature request.

Is there a way to normalise differences in request.url when http firebase-functions running under emulator and deploy

For firebase tools 6.9.2:
When using firebase emulators:start --only functions, hosting where the functions are invoked via a hosting rewrite rule, the functions are invoked with different request url path prefixes than if the functions were deployed to the cloud. For example given a firebase.json hosting snippet such as:
{
"target": "myapi",
"public": "./dist/hosting/myapi",
"rewrites": [{
"source": "/api/myapi/*",
"function": "myapi"
}
]
},
When deployed to firebase, the myapi function will be called with a request url that starts with:
/api/myapi/
but if run in the emulator it ends up looking like:
/[firebase-project-id]/[firebase-region]/myapi/api/myapi/
This doesn't make a difference if the function doesn't look at the request path but in my case, the function is a handler for an express (koa) handler with routes so knowing the base path is important.
I've looked to see if anything is available in process.env but only the GCLOUD_PROJECT name and a few FIREBASE_CONFIG params are there.
I could not find any documentation on more advanced control of the rewrite to a function in firebase.json.
I can work around it in testing by setting an environment variable to match the prefix the functions are running at locally and taking it into account during request handling. Unfortunately the request url prefix is not available until after the emulators are started and the function urls are logged.
I am hoping to find a better solution for testing.
This turned out to be a bug and is was resolved for my case in firebase-tools 6.10.0.
https://github.com/firebase/firebase-tools/issues/1279
This related issue was also opened:
https://github.com/firebase/firebase-tools/issues/1312

Resources