_firebase2.default.database.ref is not a function - firebase

I'm new to React Native and doing a project following some online tutorials. In given step, I have created a Firebase database (also added some dummy data and set a standard rule). In my React Native project, to fetch data after user being authenticated from Firebase, I'm doing following action :
import firebase from 'firebase';
export const loadInitialContacts = () =>
{
const {currentUser} = firebase.auth();
return (dispatch) => {
firebase.database.ref(`/users/${currentUser.uid}/people`)
.on('value', snapshot => {
dispatch({type: 'INITIAL_FETCH', payload: snapshot.val()});
});
};
};
I'm calling the above method from my list view Component :
componentWillMount()
{
this.props.loadInitialContacts();
}
Authentication to Firebase pass successfully, at the time of fetching data from Firebase it throws exception :
Error: TypeError: TypeError: _firebase2.default.database.ref is not a function
What I'm doing wrong?
Looking into the package.json, I'm on this following version :
"dependencies": {
"firebase": "^5.0.2",
"lodash": "^4.17.10",
"react": "16.3.1",
"react-native": "^0.55.4",
...
},

I faced a similar error.
My original code was:
const rootRef = firebase.database.ref().child('react');
However, I changed it to
const rootRef = firebase.database().ref().child('react');
and it worked.
Change firebase.database().ref from firebase.database.ref

Related

Error when setting up Firebase automated backup with Google Cloud Functions

I'm trying to setup automatic backup of my Firestore using instructions here: https://firebase.google.com/docs/firestore/solutions/schedule-export
I get error:
firestoreExpert
g2o6pmdwatdp
TypeError: Cannot read properties of undefined (reading 'charCodeAt')
at peg$parsetemplate (/workspace/node_modules/google-gax/build/src/pathTemplateParser.js:304:17)
at Object.peg$parse [as parse] (/workspace/node_modules/google-gax/build/src/pathTemplateParser.js:633:18)
at new PathTemplate (/workspace/node_modules/google-gax/build/src/pathTemplate.js:55:54)
Any suggestions to debug this?
I've tried looking for errors in my permissions. E.g. I don't know how to check if the service has access to the specific bucket, although the GCL ran OK.
I've also tried looking for errors in the script.
index.js
const firestore = require('#google-cloud/firestore');
const client = new firestore.v1.FirestoreAdminClient();
// Replace BUCKET_NAME
const bucket = 'gs://EDITEDHERE.appspot.com'
exports.scheduledFirestoreExport = (event, context) => {
const databaseName = client.databasePath(
process.env.GCLOUD_PROJECT,
'(default)'
);
return client
.exportDocuments({
name: databaseName,
outputUriPrefix: bucket,
// Leave collectionIds empty to export all collections
// or define a list of collection IDs:
// collectionIds: ['users', 'posts']
collectionIds: [],
})
.then(responses => {
const response = responses[0];
console.log(`Operation Name: ${response['name']}`);
return response;
})
.catch(err => {
console.error(err);
});
};
and package.json
{
"dependencies": {
"#google-cloud/firestore": "^1.3.0"
}
}
I found these great video tutorials
How to schedule firestorm backups and
How To Transfer Firestore Data From One Project To Another

Create a user programatically using Firebase Auth emulator

I am trying to write jest tests using the Firebase Auth emulator and continue to receive the following CORS error.
console.error
Error: Headers X-Client-Version forbidden
at dispatchError (/Users/me/my-project/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:62:19)
at validCORSPreflightHeaders (/Users/me/my-project/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:99:5)
at Request.<anonymous> (/Users/me/my-project/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js:367:12)
at Request.emit (events.js:315:20)
at Request.onRequestResponse (/Users/me/my-project/node_modules/request/request.js:1059:10)
at ClientRequest.emit (events.js:315:20)
at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:641:27)
at HTTPParser.parserOnHeadersComplete (_http_common.js:126:17)
at Socket.socketOnData (_http_client.js:509:22)
at Socket.emit (events.js:315:20) undefined
The test is very simple:
import { renderHook, act } from "#testing-library/react-hooks"
import faker from "faker"
import { useAuth, FirebaseProvider, firebase } from "./index"
const wrapper = ({ firebase, children }) => {
return <FirebaseProvider firebase={firebase}>{children}</FirebaseProvider>
}
const createUser = ({ email = faker.internet.email(), password = faker.internet.password({ length: 6 }) } = {}) => {
return firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then(user => user)
}
const signUserIn = ({ email, password } = {}) => {
return firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(user => user)
}
describe("useAuth", () => {
it("will return the user", async () => {
const { result } = renderHook(() => useAuth(), { wrapper, initialProps: { firebase } })
const email = faker.internet.email()
const password = faker.internet.password()
await act(async () => {
const user = await createUser({ email, password }) // this fails
await signUserIn({ email, password }) //and so does this
})
expect(result.user).toEqual({ email, password })
})
})
And for reference, the index file:
const FirebaseProvider = ({ children, firebase }) => {
const firestore = firebase.firestore()
const auth = firebase.auth()
if (useEmulator()) {
firestore.useEmulator("localhost", 8080)
auth.useEmulator("http://localhost:9099/")
}
const value = { firestore, auth }
return <FirebaseContext.Provider value={value}>{children}</FirebaseContext.Provider>
}
const throwError = hook => {
throw new Error(`${hook} must be used within a FirebaseProvider`)
}
const useAuth = () => {
const context = useContext(FirebaseContext)
if (context === undefined) throwError("useAuth")
const [user, setUser] = useState()
useEffect(() => {
const cleanup = context.auth.onAuthStateChanged(authUser => {
authUser ? setUser(authUser) : setUser(null)
})
return () => cleanup()
})
return { ...context.auth, user }
}
I have tried using the REST endpoint that the actual emulator uses (below) and it errors in the same way.
http://localhost:9099/identitytoolkit.googleapis.com/v1/projects/<my-project>/accounts
Is there anyway to get this to run when using jest? Or do I need to create the accounts using the emulator UI, export them and re-import when I am running tests?
I have found I can use the REST endpoint below to make a user in the test, however it bypasses the emulator and makes a real user.
https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=<api-key>
Update jsdom version 16.5.2
This new version now supports wildcards for access-control-allow-headers, so updating to this version or using it as resolution, for projects created with Create React App, solves the problem.
Solution for jsdom prior to version 16.5.2
The error is thrown by jsdom because it doesn't support wildcard for access-control-allow-headers, but firebase uses the wildcard (see this issue for jsdom and this pull request related to firebase). There are two open pull requests to fix this issue: https://github.com/jsdom/jsdom/pull/3073 and https://github.com/jsdom/jsdom/pull/2867.
The issue can be fixed by either changing the relevant code manually in the node_modules folder or by using the fork as dependency in the package.json:
"jsdom": "silviot/jsdom#fix/allow-headers"
If jsdom isn't a direct dependency, then you can add the following to the package.json at the top level:
"resolutions": {
"jsdom": "silviot/jsdom#fix/allow-headers"
}
If the fork is used there are some auto-generated files missing in the jsdom folder. These can be generated by running npm install or yarn install in the folder. To automate this you can add a prepare script to the package.json:
"scripts": {
"prepare": "cd node_modules/jsdom && yarn"
},
I also had problems making users programaticly in the firebase auth emulator.
Instead of using
https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]
You have to use the following format:
http://localhost:9099/identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]
Then giving a JSON body like this, and hit post
{
"email": "test#test.com",
"password": "test12"
}
And voila! You have a user in your emulator. Combine this with fetch or axios and you seed your emulator with users. If you need to add custom claims or other info, create function in the functions emulator that triggers on user creation.
functions.auth.user().onCreate

connecting to firestore emulator with #firebase/testing

I am trying to test a firebase app locally.
I am running the test with firebase emulators:exec --only firestore 'mocha -r ts-node/register src/**/*.spec.ts
In my spec, I import #firebase/testing and setup my app and followed the directions from
https://firebase.google.com/docs/rules/unit-tests
I have a FirebaseService which is a singleton wrapper for my methods into which I inject my firebase app.
In production, I'll inject the firebase, and it gets initialized in the FirebaseService in testing, I initialize outside of the service.
The wrapper is fairly simple
export const FirebaseService = (function(): FirebaseSrvc {
let firebase;
const fbServiceObj: FirebaseSrvc = {
getInstance: (firebaseConfig, firebaseCore, initialize) => {
firebase = firebaseCore;
if (initialize && firebase.apps.length === 0) {
firebase.initializeApp(firebaseConfig);
}
return fbServiceObj;
},
createActivity: async (title: string) => {
try {
const firebaseUid = firebase.auth().currentuser.uid;
const newActivity: ActivityProps = {
title,
created_at: 123445,
created_by: firebaseUid,
public: false,
available_to: [firebaseUid],
};
console.log(' before create', newActivity);
const createResponse = await firebase
.firestore()
.collection('activities')
.doc(stringToSafeId(title))
.set(newActivity);
console.log('create response', createResponse);
return true;
} catch (e) {
console.log('error creating activity', e);
}
},
getActivity: async (title: string): Promise<ActivityProps> => {
try {
const actResponse: DocumentReferenceTo<ActivityProps> = await firebase
.firestore()
.collection('activities')
.doc(stringToSafeId(title))
.get();
return actResponse as ActivityProps;
} catch (e) {
console.log('error getting activity from firebase', e);
}
},
};
return fbServiceObj;
})();
The test I am attempting to run is
import * as firebase from '#firebase/testing';
import { assert } from 'chai';
import 'mocha';
import * as appConfig from '../../app-dev.json';
import { FirebaseService } from '../services/FirebaseService';
firebase.initializeTestApp({ ...appConfig.expo.extra.firebase, auth: { uid: 'random', email: 'test#test.com' } });
describe('Activity', async () => {
const fb = FirebaseService.getInstance(appConfig.expo.extra.firebase, testApp, false);
const activityData = new Activity(fb);
beforeEach(async () => await firebase.clearFirestoreData({ projectId }));
it('should create a new activity', async () => {
await activityData.set('test-activity'); // this runs FirebaseService.createActivity
const findActivity = await activityData.get('test-activity'); // this run FirebaseService.getActivity
assert(findActivity.title === 'test-activity');
});
});
When I run the test I get an error
Your API key is invalid, please check you have copied it correctly.] {
code: 'auth/invalid-api-key',
message: 'Your API key is invalid, please check you have copied it correctly.'
}
I can confirm that the API key which is passed into firebase.initializeTestApp matches the Web API Key in my firebase console.
I have also downloaded the google-services.json from my firebase console and lists
{
"api_key": [
{ "current_key": different_from_web_key}
]
}
And I have replaced my existing key with this new key, I still get the same error.
I have also tried setting up initializeTestApp({ projectId }) which is how the example from firebase docs sets it up, and I receive the same result.
I am using the same project details to run a project locally in android studio, and I am able to authenticate and write to firestore, so the API key I am using does work, but it appears to have issues being used in the test app.
This usually doesn't have a specific way to solve it. It might be that even a new copy and paste of the API key to the parameters, might make it work and the error to disappear.
I would recommend you to take a look at the following posts from the Community, that have some possible fixes for the error that you are facing.
Firebase Error: auth/invalid-api-key, Your API key is invalid, please check you have copied it correctly
Invalid API Key supplied using Firebase
In addition to that, since Firebase has free support offers, I think you reaching out to the Firebase support would help you fix this quickly. You should be able to contact directly for free.
Let me know if the information helped you!

Sendgrid & Firebase Functions: Error Sending Transactional Email with Dynamic Template Data

Once a new vendor is registered on my Firebase Realtime Database, I want to send the new vendor a welcome email via Sendgrid. I've constructed a Firebase function newVendorEmail() to do this in my app's functions/src/index.ts folder and configured everything there as per https://app.sendgrid.com/guide/integrate/langs/nodejs/verify. I'm also able to retrieve vendor details from Firebase via onCreate() in newVendorEmail() and pass them to the dynamic_template_data part of the msg object without any problem. But when the newVendorEmail() function was triggered in Firebase Functions the email was not sent and I got this response instead in my Firebase Functions Console: TypeError: Object.values is not a function at Mail.setDynamicTemplateData (/user_code/node_modules/#sendgrid/mail/node_modules/#sendgrid/helpers/classes/mail.js:342:12). Help, please?
I've tried upgrading to the latest #sendgrid/mail npm package v6.4.0, tried switching to a new Sendgrid API key, tried storing this new API key in process.env as per Sendgrid's github example https://github.com/sendgrid/sendgrid-nodejs/blob/master/use-cases/kitchen-sink.md instead of functions.config(), but to no avail.
in node/process.env:
{ SENDGRID_API_KEY:
'SG....E',
...
}
in functions/src/index.ts:
'use strict'
const functions = require('firebase-functions')
const admin = require('firebase-admin')
const sendgrid = require('#sendgrid/mail')
// init function
admin.initializeApp()
//init firebase ref const
const ref = admin.database().ref()
// set sendgrid api from process env
sendgrid.setApiKey(process.env.SENDGRID_API_KEY)
export const newVendorEmail = functions.database
.ref('users/{userId}/profile')
.onCreate((snapshot, context) => {
// call field data using snapshot.val()
let msg
const userData = snapshot.val()
if (userData.type === 'vendor') {
// set email data
msg = {
to: userData.email,
from: {
name: 'Blk. Party',
email: '...#blkparty.com'
},
// custom templates
templateId: '...',
dynamic_template_data: {
subject: 'Welcome to Blk. Party!',
name: userData.name,
regLink: userData.regLink
},
}
}
// send email via sendgrid
return sendgrid.send(msg)
})
in package.json:
...
"dependencies": {
"#sendgrid/mail": "^6.4.0",
"firebase-admin": "~6.0.0",
"firebase-functions": "^2.1.0"
},
"devDependencies": {
"#sendgrid/mail": "^6.4.0",
...
}
...
I expect emails to be sent without any error.
I had the same problem. In my case, the solution was to switch from node6 to node8 in firebase functions.

Vue/Firestore/Firebase error on retrieve data

I am creating a Vue JS app with Firestore database but have a problem somewhere in the Firestore import (probably).
Its a simple app just storing some employee details which want to be displayed (initially) to test its working. (It doesnt!) Its just using "firebase": "^5.0.4", not vue-firebase or other plugin.
Its Firestore not the Firebase Real Time db.
So in the firebaseInit.js config file are all the basic config options which are as below
import * as firebase from 'firebase'
// Initialize Firebase
var config = {
apiKey: "AIzaSyCyKS3QxqtR9HvetpT2vWKFNxa_yeRKdhA",
authDomain: "vuefsprod-fc778.firebaseapp.com",
databaseURL: "https://vuefsprod-fc778.firebaseio.com",
projectId: "vuefsprod-fc778",
storageBucket: "vuefsprod-fc778.appspot.com",
messagingSenderId: "1048509841840"
}
firebase.initializeApp(config)
var auth = firebase.auth()
var db = firebase.database()
export function signOut (callback) {
auth.signOut().then(value => {
callback()
}, err => { callback(err) })
}
export default 'firebase/firestore'
And then the script snippet to test it is as below (in Helloworld.vue)
import db from '../firebaseInit'
export default {
name: 'home',
data () {
return {
employees: [],
loading: true
}
},
created() {
db.collections('employees').get().then(querySnapshot => {
querySnapshot.forEach(doc => {
console.log(doc)
const data = {
}
})
})
}
}
Yarn compiles the app which displays, but there is a warning error in console as below
[Vue warn]: Error in created hook: "TypeError: __WEBPACK_IMPORTED_MODULE_0__firebaseInit__.a.collections is not a function"
found in
---> <Home> at src/components/HelloWorld.vue
and no data is displayed to the console, there are 6 items in the employees collection.
I'm also wondering where the "a" in a.collections comes from.
Any tips on this or a better way of doing it, say with vue-firebase or other, are more than welcome. Screenshot below.
Many Thanks
You are declaring the database with the Real Time Database (RTDB) service, instead of the Firestore service:
var db = firebase.database() // <- RTDB
You should do the following instead:
var db = firebase.firestore()
Since the RTDB does not have collections, you receive the error "collections is not a function"
FYI, the different available services are documented here: https://firebase.google.com/docs/web/setup#use_firebase_services, together with how to access/declare them.
The issue is on how you retrieving data from the firebase db
db.collections('employees')
Kindly update it to
db.collection('employees')
This should resolve this .

Resources