How to catch a frontend call to a non-existing function - firebase

Is there a way to catch a not existing API call in the Firebase functions?
I'm trying to handle a situation when the frontend application trying to get a response from a cloud function that doesn't exist.
http://localhost:5001/<appid>/us-central1/someBadApi
I'm getting a generic response:
Function us-central1-someBadApi does not exist, valid functions are: us-central1-getUserCompleteData, us-central1-getDevices, ...
I would like to intercept such errors on the server side, and return a JSON instead.
PS: I'm not using express, just functions.https.onRequest functions.

Related

Gatsby Deployment Issue

I have a javascript file hubspot.js on src/api folder of my gatsby project which become functions automatically with paths based on their file name (according to Gatsby Documentation).
This API is called when submitting one form which should create a contact in hubspot.
When I run the project in development, it successfully returns the response and contact is created. But, while using "serve public" to test in production, it returns:
POST http://localhost:3000/api/hubspot 404 (Not Found)
and also in deploying using nginx configuration, it returns 405 error.
I also have another api function called status which is like this and is a GET api.
export default function handler(req, res) {
res.status(200).json({ status: 'ok' });
}
Even this function is not called and returns not found error.
I don't have any backend as gatsby can handle that part by itself, as described here.
Functions let you build dynamic applications without running servers. Submit forms, authenticate users, securely connect to external services, build GraphQL/REST APIs, and more.
Gatsby Function
So, even in production, this must be handled and the api should be called when the form submits or when I make a GET request to /api/status.
But, all I am getting is 404 not found and 405 error.

Return Browser-Understandable Status Code with Callable Firebase Cloud Functions

I'm aware that a status code that is interpretable by the browser can be sent via Firebase Cloud Functions when using the onRequest method, however, I would like to return a status code using on callable (i.e., onCall) implementation.
I don't want to simply return an arbitrary JSON object such as
{
status: 401
}
because the browser won't flag that.
Do callable Firebase Cloud Functions support browser-recognisable status codes?
Edit
I found documentation referring to method of throwing an error via e.g.:
throw new functions.https.HttpsError(
'permission-denied',
'Must be an administrative user to initiate delete.'
);
The question still stands though, what about other statuses (e.g., 201)

Custom logging from firebase function

I'm trying to follow this guide to put some custom logging into a firebase function. The function itself is running, and I can see the data being passed in (it's an https 'callable' function). But as soon as it hits the line where it tries to actually write that log entry, I get "Error: 7 PERMISSION_DENIED"
Since the console.log() calls write to the cloud logs, I'd assumed the firebase function has access to Cloud Logging. But perhaps it needs additional permission? I can't find any reference to where this should be set on that page though.
// Logging, logName, region, functions are provided by the surrounding app
const logging = new Logging()
const log = logging.log(logName)
const METADATA = {
resource: {
type: 'cloud_function',
labels: {
function_name: 'CustomLog',
region
}
}
};
exports = module.exports = functions.https.onCall(async data => {
const exVersion = 6
const exId = data.exId
console.log('***** exVersion:', exVersion, 'exId:', exId) // exId from caller
const entry = log.entry(METADATA, data.error) // data.error from caller
console.log('METADATA:', METADATA) // Shows in Logs Explorer
console.log('entry:', entry) // Shows in Logs Explorer
log.write(entry) // Results in Error: 7 PERMISSION_DENIED
return {
exVersion,
exId,
}
})
If I run it from the CLI using firebase function:shell, the log entry is created correctly, so I'm pretty confident the code is correct.
OK, I finally tracked it down. According to this answer, the service account used by firebase functions is {project-id}#appspot.gserviceaccount.com, and in my project, that account did not have the 'Logs Writer' role. Adding that role solves the problem.
I find it odd that the firebase functions don't need that role to log messages using console.log(), but perhaps that call is intercepted by the functions environment, and the logs are written as a different service account. It also explains why the functions running locally were able to write the logs, as they run using the 'owner' service account, which has full access.
According to the Firebase documentation page you have linked:
The recommended solution for logging from a function is to use the
logger SDK. You can instead use standard JavaScript logging calls such
as console.log and console.error, but you first need to require a
special module to patch the standard methods to work correctly:
require("firebase-functions/lib/logger/compat");
Once you have required the logger compatibility module, you can use console.log() methods as normal in your code.
Thus you might to require this library, however I am not sure this is producing your "Error: 7 PERMISSION_DENIED error, but you might also try some solutions that have worked for some members of the community.
Perhaps the logging API is not enabled in your project. You'll get a permission denied error when attempting to use it in that case.
It's a couple levels in, but the guide you linked points to
https://github.com/googleapis/nodejs-logging#before-you-begin, which includes a step to "Enable the Cloud Logging API"

firebase callable functions returning CORS error and not being called from client

I have been using firebase functions for quite some time and all deployments of functions have been going quite smoothly. All of a sudden any new functions deployed have stopped working and any calls from the client return a CORS error. If I check the functions list in the firebase dashboard I can't see the functions being called which is similar to what I would expect if the functions simply didn't exist at all.
I am now just trying a simple basic function like below:
exports.createSession = functions.region('europe-west2').https.onCall(async (data, context) => {
return ({status: 200})
});
On the frontend I am doing a simple call like below:
const createSessionFunction = functions.httpsCallable('createSession');
const response = await createSessionFunction({});
All the other functions that were create and deployed prior to this week are working fine. Any new functions are not.
The error I get is below:
Access to fetch at 'https://europe-west2-xxxxxxx.cloudfunctions.net/createSession' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
index.cjs.js:614 POST https://europe-west2-xxxxxxxz.cloudfunctions.net/createSession net::ERR_FAILED
My function list on the firebase GUI show this function does exist:
createSession - Request - https://europe-west2-xxxxxxxx.cloudfunctions.net/createSession-europe-west2-Node.js 8 -256 MB - 60s
However the logs show that it is never called from the client when I'm trying to test it which means the client might not be detecting this function at all.
I have tried the following steps with no luck:
Delete and redeploy the functions
Rename the function and redeploy
Deploy the same new function on different applications (dev/test etc)
Any ideas?
This was resolved on the google cloud dashboard by granting all my functions public access. The default permissions has changed from public to private.
https://cloud.google.com/functions/docs/securing/managing-access-iam#allowing_unauthenticated_function_invocation

Why do I get auth'ed when I test hitting my Firebase Cloud Function in a browser?

I have a Firebase Cloud Function that handles HTTP requests, using:
export const foo = functions.https.onRequest((req, res) => {
// etc.
}
When I hit the URL for it in a browser, I see a Google sign in page, listing my Google accounts. If I sign in, I then get a 403:
Error: Forbidden
Your client does not have permission to get URL /foo from this server.
Why? There's nothing about this in the docs that I can find. I'm on the free plan ("Spark"), if that makes any difference.
[edit]
I'm accessing the function using the URL:
https://us-central1-[project name].cloudfunctions.net/[function name]
There's no vanity URL.
The 403 message is originating from the main url https://us-central1-[project-name].cloudfunctions.net/ which is fully managed by Google.
It seems cloud functions does not have an error handling for non-existing functions name. Thus everything that is not created are treated the same way as a forbidden link. I don't know if this is an intended behavior but since the functions are running on a managed environment, there's not much handling of not existing functions against your project cloud function url.
The following statement from the link above explains it all:
"Cloud Functions run in a fully-managed, serverless environment where Google handles infrastructure, operating systems, and runtime environments completely on your behalf. Each Cloud Function runs in its own isolated secure execution context, scales automatically, and has a lifecycle independent from other functions. "
Hope this helps.

Resources