admin.database is not a function - javascript

Iam using firebase admin but when I use exports like
var admin = require('firebase-admin');
var serviceAccount = require('./firebaseconfig.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://database.firebaseio.com"
});
module.exports = { admin : admin }
and used in another file by require like
var admin = require('../Firebaseconfig/firebase.js');
console.log(admin.database())
then gives error while starting the server
but if iam using admin.database() in the same file then Iam not getting any error.
error snippet:
console.log(admin.database())
TypeError: admin.database is not a function
at Object.

You exported an object containing admin. So you have to use admin.admin.database() :D
Or just export admin. module.exports = admin

Related

How do i solve the "status":{"code":3,"message":"INVALID_ARGUMENT"} error in firebase functions console?

I am using ReactJS with Firebase to make functions. My motive is to create a user signup function. Following is the code for it.
app.post( '/signup', (req, res)=> {
const newUser = {
email : req.body.email,
password : req.body.password,
confirmPassword : req.body.confirmPassword,
handle : req.body.handle,
};
firebase.auth().createUserWithEmailAndPassword('newUser.email', 'newUser.password')
.then((data)=>{
return res.json({message: `user signed up successfully`});
} ).catch( (err) => { console.error(err); return res.json({error : err.code}) } );
} )
It also requires the use of Firebase initialization with proper credentials. The code i am including below :
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const app = require('express')();
const firebase = require('firebase');
const firebaseConfigg = {
apiKey: "A*************************s",
authDomain: "socialape-9ede9.firebaseapp.com",
databaseURL: "https://socialape-9ede9.firebaseio.com",
projectId: "socialape-9ede9",
storageBucket: "socialape-9ede9.appspot.com",
messagingSenderId: "105*****9789",
appId: "1:1054747689789:web:075f037f03b59627edfb54",
measurementId: "G-ZY1LNR052N"
};
admin.initializeApp();
firebase.initializeApp(firebaseConfigg);
The firebase functions log is showing this error when i try to run firebase deploy :
How to get through this error? I have been following this youtube tutorial link :Youtube social networking website tutorial with react and firebase and around 42.55min the guy uses firebase authentication, and copies a code in project settings, which seems to be different for me (obvioously i am not expecting the same api keys etc, but the format, it actually asks me to add a web app, but not in the tutorial) when i go through the exact same steps, snippet for me looks like the const firebaseconfig that i gave in the code snippet above.
My VS Code says:
Error: Functions did not deploy properly.
In a Cloud Function, you need to use the Admin SDK if you want to interact with one of the Firebase services (Auth, Firestore, Cloud storage, etc.).
So, you need to adapt you code as follows:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const app = require('express')();
admin.initializeApp();
//...
app.post( '/signup', (req, res)=> {
const newUser = {
email : req.body.email,
password : req.body.password,
// see https://firebase.google.com/docs/reference/admin/node/admin.auth.UserRecord
};
admin.auth().createUser(newUser)
.then((data)=> {
return res.send({message: `user signed up successfully`});
})
.catch((err) => {
console.error(err);
return res.status(500).send({error : err.code}) });
});
See also https://firebase.google.com/docs/auth/admin/manage-users?authuser=0#create_a_user.

initialize firebase app in multiple files with nodejs

I want to Initialize Firebase App in multiple files to organize my methods properly, but I not sure which is the best way to do so.
Below is the file system structure:
/functions
|-keys
|-methods
| |-email.js
| |-logger.js
|-node_modules
|-index.js
|-package.json
|-package-lock.json
In my index.js, I initialize 2 projects where 1 is for production and another is for OTE.:
const functions = require('firebase-functions');
var firebaseAdmin = require('firebase-admin');
var productionServiceAccount = require('./keys/production-key.json');
var oteServiceAccount = require("./keys/ote-key.json");
var prodServer = firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(productionServiceAccount),
databaseURL: 'https://production-panel.firebaseio.com'
}, "prod");
var oteServer = firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(oteServiceAccount),
databaseURL: "https://ote-panel.firebaseio.com"
}, "ote");
console.log("prodServer: ", prodServer.name, "oteServer: ", oteServer.name)
var mailer = require('./methods/email.js') //import code from method folder
var logger = require('./methods/logger.js') //import code from method folder
Below is how i handle the request whether use prod or OTE project:
let admin = req.headers.env == 'prod' ? prodServer : oteServer
Now the problem is my ./methods/logger.js want to read/write log into DB as well, but I don't know how/what to do.
Below is the `logger.js` code:
var exports = {}
exports.log = function(item, ref, env) {
let admin = env == 'prod' ? prodServer : oteServer //<--problem here
return admin.database().ref(ref).push(item)
}
module.exports = exports
Should I initialize firebase project again or import it from index.js?
-If initialize firebase project again it will say the project "name" has been used.
-If import it from index.js, then I have to export it from index.js, which when I deploy it to Firebase Function, it will become an onCall Methods..?
-If I move the initialize to another file (./method/initFirebase.js) and import it to index.js when I deploy it to Firebase Function, will it automatically initialize the firebase app?
Please advise. Thank you.
You can create one additional file like you said initFirebase.js and put your initilization and export code there.
const prodServer = firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(productionServiceAccount),
databaseURL: 'https://production-panel.firebaseio.com',
}, 'prod');
const oteServer = firebaseAdmin.initializeApp({
credential: firebaseAdmin.credential.cert(oteServiceAccount),
databaseURL: 'https://ote-panel.firebaseio.com',
}, 'ote');
module.exports = {
firebaseApp: env === 'prod' ? prodServer : oteServer,
};
And from all other file import firebase app
const firebaseApp = require('../YOUR_initFirebase.js')
So you dont need to worry about environment in each of the files and it is working for me on google cloud functions.
Here is how you can manage multiple apps with firebase-admin on nodejs to ensure the apps are not reinitialised.
const admin = require('firebase-admin');
const service1 = require('./app1-service.json');
const service2 = require('./app2-service.json');
const apps = {
app1: null,
app2: null,
};
void init() {
// check and init app1
const initialisedApps = admin.apps.map((item) => item.name);
if (!initialisedApps.includes('app1')) {
apps.app1 = admin.initializeApp({
credential: admin.credential.cert(service1),
}, 'app1');
} else apps.app1 = admin.app('app1');
// check and init app2
if (!initialisedApps.includes('app2')) {
apps.app2 = admin.initializeApp({
credential: admin.credential.cert(service2),
}, 'app2');
} else apps.app2 = admin.app('app2');
}
The way I solved this for ts is:
index.ts
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(functions.config().firebase);
exports.auth = require('./methods/email.ts');
...
email.ts
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
// Get emails
exports.getEMail = functions.https.onCall(async (data, context) => {
const uid = context?.auth?.uid ? context.auth.uid : '';
const email = await admin.firestore().collection('emails').doc(uid).get();
return email;
...

admin.auth().setCustomUserClaims "is not a function"

In a Firebase Cloud Function running Express, I am attempting to set custom user claims when a client posts a token to a setCustomClaims route. When I call admin.auth().setCustomUserClaims(uid, {admin: true}) within that route, I get an error saying this is "not a function."
My authentication provider is the email/password provider via Firebase authentication (i.e. I am not creating custom tokens).
Do I have to be creating custom tokens to set custom user claims?
Here is my cloud function code:
const functions = require('firebase-functions');
const admin = require("firebase-admin");
import express from "express"
admin.initializeApp(functions.config().firebase);
const app = express()
app.post('/setCustomClaims', (req, res) => {
uid = "some-uid"
admin.auth().setCustomUserClaims(uid, {admin:true}).then(()=> {
res.end(JSON.stringify( { status: 'success' } ) );
})
});
export let api = functions.https.onRequest((request, response) => {
if (!request.path) {
request.url = `/${request.url}` // prepend '/' to keep query params if any
}
return app(request, response)
})
npm install firebase-admin#latest --save
firebase-admin#5.4.3 work, good luck for fun app.
Note: client needs this code
// Force token refresh. The token claims will contain the additional claims.
firebase.auth().currentUser.getIdToken(true);
In the new SDKs, you no longer instantiate a database references via new Firebase. Instead, you will initialize the SDK via firebase.initializeApp():
BEFORE
var ref = new Firebase("https://databaseName.firebaseio.com");
AFTER
// See https://firebase.google.com/docs/web/setup#project_setup for how to
// auto-generate this config
var config = {
apiKey: "apiKey",
authDomain: "projectId.firebaseapp.com",
databaseURL: "https://databaseName.firebaseio.com"
};
firebase.initializeApp(config);
var rootRef = firebase.database().ref();>
I have found same issue on the stackoverflow, check this: firebase.database is not a function

firebase.auth.GoogleAuthProvider is undefined

I'm using Firebase to authenticate a user. I have setup Firebase like so:
firebase.js
const firebase = require("firebase-admin")
const serviceAccount = require("./serviceAccountKey.json")
firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount),
databaseURL: "https://logbook-96180.firebaseio.com/"
})
module.exports = firebase
I then import firebase in another file to authenticate a user.
auth.js
const firebase = require("./firebase")
...
const credential = firebase.auth.GoogleAuthProvider.credential(
null,
accessToken
)
firebase.auth().signInWithCredential(credential)
When I execute the authentication, I receive an error Cannot read property 'credential' of undefined, showing that firebase.auth.GoogleAuthProvider is undefined.
Are there any reasons as to why this could be the case? Thanks.

Upload files to Firebase Storage using Node.js

I'm trying to understand how to upload files in Firebase Storage, using Node.js. My first try was to use the Firebase library:
"use strict";
var firebase = require('firebase');
var config = {
apiKey: "AIz...kBY",
authDomain: "em....firebaseapp.com",
databaseURL: "https://em....firebaseio.com",
storageBucket: "em....appspot.com",
messagingSenderId: "95...6"
};
firebase.initializeApp(config);
// Error: firebase.storage is undefined, so not a function
var storageRef = firebase.storage().ref();
var uploadTask = storageRef.child('images/octofez.png').put(file);
// Register three observers:
// 1. 'state_changed' observer, called any time the state changes
// 2. Error observer, called on failure
// 3. Completion observer, called on successful completion
uploadTask.on('state_changed', function(snapshot){
...
}, function(error) {
console.error("Something nasty happened", error);
}, function() {
var downloadURL = uploadTask.snapshot.downloadURL;
console.log("Done. Enjoy.", downloadURL);
});
But it turns out that Firebase cannot upload files from the server side, as it clearly states in the docs:
Firebase Storage is not included in the server side Firebase npm module. Instead, you can use the gcloud Node.js client.
$ npm install --save gcloud
In your code, you can access your Storage bucket using:
var gcloud = require('gcloud')({ ... }); var gcs = gcloud.storage();
var bucket = gcs.bucket('<your-firebase-storage-bucket>');
Can we use gcloud without having an account on Google Cloud Platform? How?
If not, how come that uploading files to Firebase Storage from the client side is possible?
Can't we just create a library that makes the same requests from the server side?
How is Firebase Storage connected with Google Cloud Platform at all? Why Firebase allows us to upload images only from the client side?
My second try was to use the gcloud library, like mentioned in the docs:
var gcloud = require("gcloud");
// The following environment variables are set by app.yaml when running on GAE,
// but will need to be manually set when running locally.
// The storage client is used to communicate with Google Cloud Storage
var storage = gcloud.storage({
projectId: "em...",
keyFilename: 'auth.json'
});
storage.createBucket('octocats', function(err, bucket) {
// Error: 403, accountDisabled
// The account for the specified project has been disabled.
// Create a new blob in the bucket and upload the file data.
var blob = bucket.file("octofez.png");
var blobStream = blob.createWriteStream();
blobStream.on('error', function (err) {
console.error(err);
});
blobStream.on('finish', function () {
var publicUrl = `https://storage.googleapis.com/${bucket.name}/${blob.name}`;
console.log(publicUrl);
});
fs.createReadStream("octofez.png").pipe(blobStream);
});
When using the firebase library on a server you would typically authorize using a service account as this will give you admin access to the Realtime database for instance. You can use the same Service Account's credentials file to authorize gcloud.
By the way: A Firebase project is essentially also a Google Cloud Platform project, you can access your Firebase project on both https://console.firebase.google.com and https://console.cloud.google.com and https://console.developers.google.com
You can see your Project ID on the Firebase Console > Project Settings or in the Cloud Console Dashboard
When using the gcloud SDK make sure that you use the (already existing) same bucket that Firebase Storage is using. You can find the bucket name in the Firebase web config object or in the Firebase Storage tab. Basically your code should start like this:
var gcloud = require('gcloud');
var storage = gcloud.storage({
projectId: '<projectID>',
keyFilename: 'service-account-credentials.json'
});
var bucket = storage.bucket('<projectID>.appspot.com');
...
Firebase Storage is now supported by the admin SDK with NodeJS:
https://firebase.google.com/docs/reference/admin/node/admin.storage
// Get the Storage service for the default app
var defaultStorage = firebaseAdmin.storage();
var bucket = defaultStorage.bucket('bucketName');
...
Firebase Admin SDK allows you to directly access your Google Cloud Storage.
For more detail visit Introduction to the Admin Cloud Storage API
var admin = require("firebase-admin");
var serviceAccount = require("path/to/serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: "<BUCKET_NAME>.appspot.com"
});
var bucket = admin.storage().bucket();
bucket.upload('Local file to upload, e.g. ./local/path/to/file.txt')
I hope It will useful for you. I uploaded one file from locally and then I added access Token using UUID after that I uploaded into firebase storage.There after I am generating download url. If we hitting that generate url it will automatically downloaded a file.
const keyFilename="./xxxxx.json"; //replace this with api key file
const projectId = "xxxx" //replace with your project id
const bucketName = "xx.xx.appspot.com"; //Add your bucket name
var mime=require('mime-types');
const { Storage } = require('#google-cloud/storage');
const uuidv1 = require('uuid/v1');//this for unique id generation
const gcs = new Storage({
projectId: projectId,
keyFilename: './xxxx.json'
});
const bucket = gcs.bucket(bucketName);
const filePath = "./sample.odp";
const remotePath = "/test/sample.odp";
const fileMime = mime.lookup(filePath);
//we need to pass those parameters for this function
var upload = (filePath, remoteFile, fileMime) => {
let uuid = uuidv1();
return bucket.upload(filePath, {
destination: remoteFile,
uploadType: "media",
metadata: {
contentType: fileMime,
metadata: {
firebaseStorageDownloadTokens: uuid
}
}
})
.then((data) => {
let file = data[0];
return Promise.resolve("https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent(file.name) + "?alt=media&token=" + uuid);
});
}
//This function is for generation download url
upload(filePath, remotePath, fileMime).then( downloadURL => {
console.log(downloadURL);
});
Note that gcloud is deprecated, use google-cloud instead.
You can find SERVICE_ACCOUNT_KEY_FILE_PATH at project settings->Service Accounts.
var storage = require('#google-cloud/storage');
var gcs = storage({
projectId: PROJECT_ID,
keyFilename: SERVICE_ACCOUNT_KEY_FILE_PATH
});
// Reference an existing bucket.
var bucket = gcs.bucket(PROJECT_ID + '.appspot.com');
...
Or you could simply polyfill XmlHttpRequest like so -
const XMLHttpRequest = require("xhr2");
global.XMLHttpRequest = XMLHttpRequest
and import
require('firebase/storage');
That's it. All firebase.storage() methods should now work.

Categories

Resources