Firebase Cloud functions - Failed to load function definition from source: Restful Endpoints - Failed to add the endpoint defined - node.js

I am using firebase cloud functions with typescript in node 16.14.
My index.ts look like this:
import { FunctionParser } from "firebase-backend";
exports = new FunctionParser({rootPath: __dirname, exports,
verbose:true}).exports;
Here is the addEvent.endpoint.ts:
import { Request, Response } from "express";
import { Endpoint, RequestType } from "firebase-backend";
// import * as functions from "firebase-functions";
const fs = require('firebase-admin');
const serviceAccount = require('./key.json');
fs.initializeApp({
credential: fs.credential.cert(serviceAccount)
});
const db = fs.firestore();
export default new Endpoint(
"addEvent",
RequestType.POST,
(request: Request, response: Response) => {
const message = request.body["message"];
db.collection("events").doc("adkakjagjh").set("message", message);
return response.status(201).send({
message: message
});
}
)
I have the following file structure as below.
My cloud functions worked just recently but some change that I am not aware of has made them error out with the following error for just this 1 endpoint "addEvent.endpoint.ts": Error: Failed to load function definition from source: Failed to generate manifest from function source: Error: Restful Endpoints - Failed to add the endpoint defined in C:/Development/EventFeeder/Backend/Firebase/functions/lib/users/restful/addEvent.endpoint.js to the users Api.
How can I fix this issue?
I am not sure what I need to try because the error message is not that specific about the problem's root cause.
I did not find any post about this particular problem.
I try to run the functions with "npm run build && firebase emulators:start --only functions" and "firebase emulators:start"
The issue disappear when I remove the addEvent.endpoint.ts file

I was facing the same problem, and I figured out that you shouldn't initialize the app (initializeApp()) in each endpoint, just write it in the index.ts one time and everything will work as expected.

Related

Firebase getAuth() throws error getProvider of undefined but can access database

I have the following code running on a Node server.
import admin from 'firebase-admin';
import {getAuth} from 'firebase/auth';
class MyFirebase {
constructor() {
console.log("MyFirebase Constructor");
this.firebaseApp = admin.initializeApp({
credential: admin.credential.cert("PATH_TO_CERT/cert.json"),
databaseURL: "https://DATABASE_URL",
});
console.log("App name="+firebaseApp.name);
this.defaultAuth = getAuth(firebaseApp);
this.database = this.firebaseApp.database();
// database ref code here...
}
}
and it throws the following error:
return app.container.getProvider(name);
TypeError: Cannot read property 'getProvider' of undefined
If I remove "firebaseApp" from the getAuth(..) call I get this error:
No Firebase app '[DEFAULT'] has been created - call Firebase
App.initializeApp() (app/no-app)
However the "console.log("App Name...")" line produces:
App name=[DEFAULT]
So clearly a DEFAULT app has been created. Additionally if I remove the "getAuth..." call the database calls pulling data from the realtime database below it work just fine, which seem to imply the authentication worked properly because I can access data from the database.
What the heck is going on?
You are confusing Firebase Admin SDK (Node.js) with Firebase Javascript SDK. The former is for the back-end, while the latter is for the front-end. I understand your confusion because the front-end package/s are installable via NPM, although they are meant to be bundled with front-end code.
You can't do this:
import admin from 'firebase-admin' // back-end code
import { getAuth } from 'firebase/auth' // front-end code !!!
const adminApp = admin.initializeApp(...)
getAuth(adminApp) // TypeScript actually catches this error
/*
Argument of type 'App' is not assignable to parameter of type 'FirebaseApp'.
Property 'automaticDataCollectionEnabled' is missing in type 'App' but required in type 'FirebaseApp'.ts(2345)
app-public.d.ts(92, 5): 'automaticDataCollectionEnabled' is declared here.
const adminApp: admin.app.App
*/
If you are on the back-end, just use adminApp.auth() to get the Auth instance. If on the front-end, you need to call getAuth with the front-end Firebase App instance:
import { initializeApp } from 'firebase/app'
import { getAuth } from 'firebase/auth'
const app = initializeApp(...)
const auth = getAuth(app)
The new modular apis have a slightly different syntax. The following should still work if you wrap it in a class, but as long as you only do this once at the top of your express? server you shouldn't need to use a class.
Also, I'm using the require syntax but imports should work too depending on your setup.
//Import each function from the correct module.
const { initializeApp, applicationDefault } = require("firebase-admin/app");
const { getAuth } = require("firebase-admin/auth");
const { getDatabase } = require("firebase-admin/database");
const app = initializeApp({
credential: applicationDefault(), //Don't forget to export your configuration json https://firebase.google.com/docs/admin/setup
databaseURL: "https://DATABASE_URL",
});
const auth = getAuth(app)
const database = getDatabase(app)
It's not super well documented but you can find hints in the Admin SDK reference: https://firebase.google.com/docs/reference/admin/node/firebase-admin.auth
One tip: In VSCode you should see the a description of each function when you hover over them, if you have the import path formatted correctly.

Firebase Cloud Function Keep return "Request failed with status code 404"

I created some functions in firebase cloud functions, but all of them are works. But i have a new function which is not work properly. I don't know why but i think it has same pattern with others.
this is my code:
const functions = require('firebase-functions');
const appVideo = express();
const cors = require('cors')({ origin: true });
appVideo.use(cors);
appVideo.get('/update-video', async(req, res) => {
console.log('updateStatusVideo idCourse', req.query.idCourse, ' idMateri: ', req.query.idMateri, ' idVideo:', req.query.idVideo);
res.status(200).send('Oke')
})
exports.video = functions.https.onRequest(appVideo)
I often call partial deploy like
firebase deploy --only functions:video. But when i execute the functions https through browser it often return
Request failed with status code 404
other weird things is when i inspect the browser and switch to console, i found
Failed to load resource: the server responded with a status of 500 ()
this is the url of function in firebase:
https://us-central1-my-apps.cloudfunctions.net/video [modified for confidential]
Please help
When you export this line:
exports.video = functions.https.onRequest(appVideo);
You define a Cloud Function called video that is deployed as https://us-central1-PROJECT_ID.cloudfunctions.net/video where PROJECT_ID is whatever your Firebase Project ID is.
Because you use a express application for this exported function, any URL that is handled must first start with https://us-central1-PROJECT_ID.cloudfunctions.net/video (the BASE_URL).
This line:
appVideo.get('/update-video', ...)
attaches a listener to BASE_URL/update-video, which becomes https://us-central1-PROJECT_ID.cloudfunctions.net/video/update-video.
If you want to use just https://us-central1-PROJECT_ID.cloudfunctions.net/video as-is, you'll need to change to using
appVideo.get('/', ...)
If you want to use just https://us-central1-PROJECT_ID.cloudfunctions.net/update-video, you'll need to change to using
appVideo.get('/', ...)
and
exports.update = {};
exports.update.video = functions.https.onRequest(appVideo);
// "update.video" is deployed as "update-video"
Note: This last part abuses deploying groups to get the desired URL

cloud functions - export from .TS to .JS index

My project cloud functions are built-in javascript and I've decided to slowly migrate it to typescript file by file.
I'm trying to export my onCall function from a TypeScript file on my index.js to firebase cloud functions but I keep receiving the following error into the terminal
"Error: Error parsing triggers: Cannot find module './business'" when trying to deploy and not being able to properly import the Typescript function into my index.js
index.js
const business = require('./business');
exports.business.processBusinessSignUp;
business.ts:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import * as api from "./api";
import { BusinessFirestoreModel } from "./ts models/business_firestore_model";
module.exports.processBusinessSignUp = functions.https.onCall((data, context) => {
const business_model = new BusinessFirestoreModel(data.fullName, data.businessName, data.email, data.address, data.phone, Date.now());
return signBusinessUp(business_model);
});
const signBusinessUp = async (business: BusinessFirestoreModel) => {
const firestoreRef = admin.firestore().collection('pending_business').doc();
return await api.callFirestoreSet(firestoreRef, business.toJSON());
}
Any ideas?
Thank you!
As Brian Burton said You need to transpile your TypeScript into regular JavaScript before deploying if you want to run Typescript natively On Firebase Cloud Function, if you want more information here is the official documentation

Firebase Functions: Upload Error: HTTP Error: 400, Unknown Error

I tried to deploy the server side of my Angular Universal SSR app to Firebase Functions, but ran into the error Upload Error: HTTP Error: 400, Unknown Error.
From what I understand, this error happens pretty often when the deployment is a huge file (in my case it's 438mb). The reason it's so big is because I'm deploying localized versions of my website so dist/browser and dist/server both have en, de, and fr directories with pretty much the same content. How can I solve this issue?
console output
=== Deploying to 'PROJECT_NAME'...
i deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run lint
+ functions: Finished running predeploy script.
i functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i functions: ensuring required API cloudbuild.googleapis.com is enabled...
+ functions: required API cloudfunctions.googleapis.com is enabled
i functions: preparing dist directory for uploading...
i functions: packaged dist (438.04 MB) for uploading
! functions: Upload Error: HTTP Error: 400, Unknown Error
Error: HTTP Error: 400, Unknown Error
index.js
const functions = require('firebase-functions');
// Increase readability in Cloud Logging
require("firebase-functions/lib/logger/compat");
const expressApp = require('./server/proxy').app();
exports.ssr = functions
.region('us-central1')
.runWith({})
.https
.onRequest(expressApp);
proxy.ts (which gets compiled to js and put into the dist/server folder)
import * as express from 'express';
import * as cookieParser from 'cookie-parser';
import { join } from 'path';
export function app() {
const server = express();
server.use(cookieParser());
const languages = ['en', 'de', 'fr'];
languages.forEach((locale) => {
const appServerModule = require(join(__dirname, locale, 'main.js'));
server.use(`/${locale}`, appServerModule.app(locale));
});
server.get('/(:locale(en|fr|de)/)?*', (req, res, next) => {
const { locale } = req.params;
let userLocale = (req.headers['accept-language'] || '').substring(0, 2);
if(!languages.includes(userLocale)) {
userLocale = 'en';
}
if (locale !== userLocale) {
res.redirect(userLocale + req.url);
}
});
return server;
}
function run() {
app().listen(4200, () => {
console.log(`Node Express server listening on http://localhost:4200`);
});
}
run();
I had the same problem with NextJS and firebase functions,
Here is my solution:
Remove node_modules and run npm i
Remove cache files, out or public builds
Check functions console registry from firebase panel (here you can check your serve status/logs)
I hope this could help to someone.
I decreased the size of my deployment, and it immediately fixed the issue. I would say you just have to optimize the files you have, or think about storing some files in another location other than the firebase functions codebase (perhaps firebase storage)
I had this issue and just was able to fix it. In my case I had deployed to firebase a number of times and with each deploy the upload directory got bigger and bigger. I ended up changing my hosting settings to only keep the last 3 deploys which ended up dropping my package size from around 170MB to 15MB once the previous deploys were deleted. For some reason with each deploy it would take in each previous deploy when trying to upload a new release which doesn't make sense to me.

Node modules with sub-directories: "Error parsing triggers: Cannot find module 'ibm-watson'"

I have a Firebase Cloud Function that calls IBM Watson to get a token. I'm updating it from the old username/password auth to the current IAM auth.
Here's the code from the IBM documentation:
const watson = require('ibm-watson');
const { IamAuthenticator } = require('ibm-watson/auth');
// to get an IAM Access Token
const authorization = new watson.AuthorizationV1({
authenticator: new IamAuthenticator({ apikey: 'fakekey-1234' }),
});
authorization.getToken(function (err, token) {
if (!token) {
console.log('error: ', err);
} else {
// Use your token here
}
});
When I run firebase deploy --only functions I get this error:
Error: Error parsing triggers: Cannot find module 'ibm-watson'
Require stack:
- /Users/TDK/LanguageTwo/functions/index.js
- /Users/TDK/.nvm/versions/node/v13.10.1/lib/node_modules/firebase-tools/lib/triggerParser.js
ibm-watson is installed in my /functions/node_modules directory:
I reinstalled ibm-watson, and for good measure I ran npm install in my functions directory. Plus I ran npm-check and updated all my node modules.
The specific line that causes the error is:
const watson = require('ibm-watson');
When I comment out that line the functions deploy without error. Unfortunately, the function doesn't run. :-)
This line does not cause the deploy error:
const { IamAuthenticator } = require('ibm-watson/auth');
I use IBM Watson in other Firebase Cloud Functions in the same index.js file. These lines from other functions don't cause deploy errors:
let TextToSpeechV1 = require('ibm-watson/text-to-speech/v1');
...
var LanguageTranslatorV3 = require('ibm-watson/language-translator/v3');
The problem seems to be that requiring the parent directory ibm-watson fails, but requiring the subdirectories of the parent directory works. Any suggestions?
This is as expected. If you take a look at the GitHub repo for ibm-watson - https://github.com/watson-developer-cloud/node-sdk - you will notice that there is no example requiring the top level library. This stops you from pulling in the full library, when you only need to pull in a small sub-component.

Resources