Firebase database triggers and Rest API in same project? - firebase

I have a Firebase cloud function project that I recently updated all the functions.https.onRequest to run through Express to create a REST API service. The APIs work fine. But when I try and deploy the project, none of the previous Firebase database triggers are deployed anymore (Example: CalculateMyStats trigger worked fine, but was removed from my cloud functions list) . Only the rest function is deployed now. Is it possible to have Rest API's and triggers in the same project?
index.ts
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
import * as http from './http';
import { AddLocationIOBookMarks, DistrubuteNotificationData, NewUserEmail } from './users/usersFuncModules';
import { AutoCheckoutCron } from './locations/locationsFuncModule';
import { CalculateMyStats } from './rating/ratingFuncModule';
import { FIREBASE_CONFIG } from './config/firebaseConfig';
import { LocationsUserCount } from './pushNotifications/pushFuncModule';
export { AddLocationIOBookMarks, DistrubuteNotificationData, NewUserEmail };
export { AutoCheckoutCron };
export { CalculateMyStats };
export { LocationsUserCount };
admin.initializeApp({
credential: admin.credential.cert({
projectId: FIREBASE_CONFIG.project_id,
clientEmail: FIREBASE_CONFIG.client_email,
privateKey: FIREBASE_CONFIG.private_key
}),
databaseURL: FIREBASE_CONFIG.databaseURL
});
admin.firestore().settings({ timestampsInSnapshots: true });
exports.rest = functions.https.onRequest(http.endpoint);
ratingFuncModule.ts
import * as express from 'express';
import * as functions from 'firebase-functions';
import * as http from '../http';
import * as myStatsModule from './calculateMystats';
import * as ratingModule from './rateUser';
import { fsConst } from '../firestoreConst';
const rateRoute = express.Router();
const cors = require('cors');
const corsOptions = http.corsOptions;
export const CalculateMyStats = functions.firestore.document(`${fsConst.USERRATINGS}/{doc-id}`).onWrite((change, context) => {
const ratedUser = change.after.data();
return myStatsModule.roundAllMyStats(ratedUser.userId).catch(error => {
console.error(new Error(error), `| Method: CalculateMyStats`);
});
});
rateRoute.get('/rate/updateRating', cors(corsOptions), (req, res) => {
const currentUserId = req.query.currentUserId;
const toBeRatedUserId = req.query.toBeRatedUserId;
const rateDocId = req.query.rateDocId;
const rateFormValues = req.query.rateFormValues;
ratingModule
.rateCurrentUser(currentUserId, toBeRatedUserId, rateDocId, rateFormValues)
.then(data => {
if (rateDocId !== 'undefined') {
res.send(JSON.stringify(rateDocId));
} else {
res.send(JSON.stringify(data));
}
})
.catch(error => {
console.error(new Error(error), `| Method: updateUserRating`);
});
});
// Export all routes for rating related http request
module.exports = rateRoute;
firebase.json
{
"functions": {
"predeploy": [
"npm --prefix $RESOURCE_DIR run lint",
"npm --prefix $RESOURCE_DIR run build"
],
"source": "functions"
},
"hosting": {
"public": "public",
"rewrites": [{
"source": "/api/v1/**",
"function": "rest"
}],
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"]
}
}
And when I deploy:
firebase deploy --only functions

You have to export all your trigger functions alongside your exports.rest in index.ts like so:
import { CalculateMyStats } from './rating/ratingFuncModule';
exports.rest = functions.https.onRequest(http.endpoint); // your existing export
exports.calculateMyStats = CalculateMyStats // trigger function export

Related

SyntaxError: Cannot use import statement outside a module next.config.js firebase pwa

After update node version I get this error in next.config.js:
import { app } from './firebase';
^^^^^^
SyntaxError: Cannot use import statement outside a module
The same when I tried to use next/dynamic and require.
But when I delete import for app I have this:
const firestore = app.firestore();
^
ReferenceError: app is not defined
I use next-pwa, CNA and I try to turn on enableIndexedDbPersistence and cacheSizeBytes for Firebase.
Before update node wersion, I didn't have import and it was ok. Now isn't wrong.
In another project I use yarn and this project npm.
My next config:
/** #type {import('next').NextConfig} */
const withPWA = require("next-pwa");
import('firebase/firestore').then(() => {
const firestore = app.firestore();
// Use Cloud Firestore ...
firestore().settings({
cacheSizeBytes: 400
});
firestore.enableIndexedDbPersistence()
.catch((e) => {
if (e.code === 'failed-precondition') {
console.error(e.code)
} else if (e.code === 'unimplemented') {
console.error(e.code)
}
});
});
module.exports = withPWA({
reactStrictMode: true,
i18n: {
locales: ['en', 'jp', 'pl'],
defaultLocale: 'en',
},
images: {
deviceSizes: [280, 320, 375, 425, 768, 1024, 1200, 1440, 2560],
loader: 'default',
domains: ['firebasestorage.googleapis.com', 's.yimg.com'],
formats: ['image/avif', 'image/webp'],
},
pwa: {
dest: "public",
register: true,
skipWaiting: true,
},
});
My firebase.js:
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
import { getStorage } from 'firebase/storage';
import { getFirestore } from 'firebase/firestore';
const firebaseConfig = {
apiKey: `${process.env.NEXT_PUBLIC_API_KEY}`,
authDomain: `${process.env.NEXT_PUBLIC_AUTH_DOMAIN}`,
projectId: `${process.env.NEXT_PUBLIC_PROJ_ID}`,
storageBucket: `${process.env.NEXT_PUBLIC_STORAGE_BUCKET}`,
messagingSenderId: `${process.env.NEXT_PUBLIC_SENDER_ID}`,
appId: `${process.env.NEXT_PUBLIC_APP_ID}`
};
export const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const db = getFirestore(app);
export const storage = getStorage(app);
Please help me.
I managed to get rid of the errors in my server console by using the older version #next-auth/firebase-adapter#1.0.1

Not sure if firebase is connected to my app and working properly

I am newbie to firebase tools and I am following a tutorial video to create an app with react and firebase. Because Ive got an error while uploading an image of either jpg or png, I wondered if firebase and my app were connected. In the video, version 7 firebase was being used and I installed version 9.6.8. I googled how to write version 9 code that functions same as code written in version 7. But still doesn't work. I guessed my app didn't properly connect to firebase as I read an error occurred.
The error is from the console of a browser.
0 null
ProgressBar.jsx:6
0 null
connection.ts:81
POST https://firebasestorage.googleapis.com/v0/b/clone-netninja-firegram.appspot.com/o?name=ssc.jpg 403
send # connection.ts:81
ProgressBar.jsx:6 0 null
ProgressBar.jsx:6 0 null
I am going to google more, but I hope someone can tackle this error.
Below are codes that I think related to the error.
Package.json file
{
"name": "firegram",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^4.2.4",
"#testing-library/react": "^9.5.0",
"#testing-library/user-event": "^7.2.1",
"firebase": "^9.6.8",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
This is a configuration file for firebase.
// import * as firebase from 'firebase/app'
import 'firebase/storage';
// import 'firebase/firestore';
//to use firebase app
// import firebase from 'firebase/app'; //older version
import firebase from 'firebase/compat/app'; //v9
//to use auth
// import 'firebase/auth'; //older version
import 'firebase/compat/auth'; //v9
//to use firestore
// import 'firebase/firestore'; //Older Version
import 'firebase/compat/firestore'; //v9
import 'firebase/compat/storage'; //v9
// Your web app's Firebase configuration
const firebaseConfig = { [[REDACTED]] };
// Initialize Firebase
// const app = initializeApp(firebaseConfig);
firebase.initializeApp(firebaseConfig);
// Initialize two services
const projectStorage = firebase.storage();
const projectFirestore = firebase.firestore();
export { projectStorage, projectFirestore };
When uploading an image
import React from 'react';
import useStorage from '../hooks/useStorage';
const ProgressBar = ({ file, setFile }) => {
const { url, progress } = useStorage(file);
console.log(progress, url)
return <div className='progress-bar'>ProgressBar</div>;
};
export default ProgressBar;
import { useState, useEffect } from 'react';
import { projectStorage } from '../firebase/config';
const useStorage = (file) => {
const [progress, setProgress] = useState(0);
const [err, setErr] = useState(null);
const [url, setUrl] = useState(null);
useEffect(() => {
// references
const storageRef = projectStorage.ref(file.name);
storageRef.put(file).on('state_changed', (snap) => {
let percentage = (snap.bytesTransferred / snap.totalBytes) * 100;
setProgress(percentage);
}, (err) => {
setErr(err)
}, async () => {
const url = await storageRef.getDownloadURL();
setUrl(url)
});
}, [file])
return { progress, url, err }
}
export default useStorage;
Just by accessing the given image url: https://firebasestorage.googleapis.com/v0/b/clone-netninja-firegram.appspot.com/o?name=ssc.jpg. It's clear that you're getting a Permission denied error:
{
"error": {
"code": 403,
"message": "Permission denied."
}
}
There are some possible reasons that you can encounter this 403 error.
If you have not configured your Firebase Storage Rules. By default Storage expects uploading users to be authenticated. If you're still on the testing phase of your project you can bypass that by writing these in the Storage > Rules:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth == null;
}
}
}
If you are ready to deploy to production, you may want to check this documentation to configure your Firebase Cloud Storage Security Rules.
If you upload a new image with the same filename and extension, it will override/replace the old image and generate a new token for it, making the old URL obsolete. You should generate a unique filename for your uploaded image and then it should be fixed.
Also, as stated by #DazWilkin, we encourage you to use a definitive tutorial on how to initialize Firebase for your project here. For Firebase Storage, you can start from here.

AngularFireModule has not been provided using v7.0.1 and new method of initializing the firebase app

I'm attempting to connect to the firebase emulator within an integration test, using the new AngularFire API (>v7)
import {
TestBed
} from '#angular/core/testing';
import {
initializeApp,
provideFirebaseApp
} from '#angular/fire/app';
import {
doc,
enableIndexedDbPersistence,
Firestore,
getFirestore,
provideFirestore,
setDoc
} from '#angular/fire/firestore';
import {
connectFirestoreEmulator
} from "firebase/firestore";
describe('FirestoreEmulatorSmoketest', () => {
let projectId: string;
let firestore: Firestore;
beforeAll(() => {
const testConfig = {
projectId,
auth: ...
};
TestBed.configureTestingModule({
imports: [
provideFirebaseApp(() => initializeApp(testConfig)),
provideFirestore(() => {
const firestore = getFirestore();
connectFirestoreEmulator(firestore, 'localhost', 8080);
enableIndexedDbPersistence(firestore);
return firestore;
}),
],
})
});
beforeEach(() => {})
afterAll(() => {})
it('should connect', () => {
const fooDoc = doc(firestore, "foo/12345");
return setDoc(fooDoc, {
updated: new Date()
})
})
});
This code produces the following error "AngularFireModule has not been provided"
I can only assume I'm not initialising angular fire somehow?
First of all, my native language is not English, so if I write like a fool you know why.
Try this.
environment.ts
export const environment = {
production: false,
useEmulators: true,
firebaseConfig: {
apiKey: 'YOUR-API-KEY',
authDomain: 'YOUR-AUTH-DOMAIN',
projectId: 'YOUR-PROJECT-ID',
storageBucket: 'YPUR-STORAGE-BUCKET',
messagingSenderId: 'YOUR-MESSAGING-SENDER-ID',
appId: 'YOUR-APP-ID',
measurementId: 'YOUR-MEASUREMENT-ID',
},
};
Important: As you can see I have the variable useEmulators, which in the following lines I will explain what it is going to be used for.
app.module.ts
import { provideFirebaseApp, initializeApp } from '#angular/fire/app';
import { getAuth, provideAuth, connectAuthEmulator } from '#angular/fire/auth';
import { getFirestore, provideFirestore, connectFirestoreEmulator, enableIndexedDbPersistence } from '#angular/fire/firestore';
import { getStorage, provideStorage, connectStorageEmulator } from '#angular/fire/storage';
import { getAnalytics, provideAnalytics } from '#angular/fire/analytics';
import { getFunctions, provideFunctions, connectFunctionsEmulator} from '#angular/fire/functions';
import { environment } from 'environments/environment'; // <--- Environment variables.
imports: [
// Firebase
provideFirebaseApp(() => initializeApp(environment.firebaseConfig)),
provideFirestore(() => {
if (environment.useEmulators) {
const firestore = getFirestore();
connectFirestoreEmulator(firestore, 'localhost', 8080);
enableIndexedDbPersistence(firestore);
return firestore;
} else {
getFirestore();
}
}),
provideAuth(() => {
if (environment.useEmulators) {
const fireauth = getAuth();
connectAuthEmulator(fireauth, 'http://localhost:9099'); // <---FireAuth Port
return fireauth;
} else {
getAuth();
}
}),
provideStorage(() => {
if (environment.useEmulators) {
const firestorage = getStorage();
connectStorageEmulator(firestorage, 'localhost', 9199); // <---- Firestorage Port
return firestorage;
} else {
getStorage();
}
}),
provideFunctions(() => {
if (environment.useEmulators) {
const firefunctions = getFunctions();
connectFunctionsEmulator(firefunctions, 'localhost', 5001); // <--- FireFunctions Port
return firefunctions;
} else {
getFunctions();
}
}),
provideAnalytics(() => getAnalytics()),
],
Important (Environment Path): Change the environment path of the variables in case you don't have them in the default location.
Important (Local Ports): In case you use different local ports than the default ones, change them.
As you can see I have added code to the initializations to be able to switch between the emulated project and the online project, in a simple way:
useEmulators: true // We load the emulator environment
useEmulators: false // We load the production environment
_fireAuth.service.ts
import { Auth } from '#angular/fire/auth';
constructor(private _fireAuth: Auth) {}
_fireStorage.service.ts
import { Storage } from '#angular/fire/storage';
constructor(private _fireStorage: Storage) {}
_fireStore.service.ts
import { Firestore } from '#angular/fire/firestore';
constructor(private _fireStore: Firestore) {}
It only remains to import the functions you are going to use, e.g. { doc, Collection, etc... }.
Use the documentation provided by Google to see how they changed the functions: https://firebase.google.com/docs/build
and use the code found in the "Web version 9 (modular)" tab.

How to configure firebase as nuxt plugin?

I am trying to configure firebase in nuxt as a plugin. I have to make the nuxtInitServer call in store because the env variables are from sharedEnv.
When the login method is invoked on the login page, I get the error:
Uncaught TypeError: _plugins_firebase__WEBPACK_IMPORTED_MODULE_3__.default.auth is not a function
store/index.js
const getSharedEnv = () =>
process.server
? {
apiKey: process.env.FIREBASE_API_KEY,
authDomain: process.env.FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.FIREBASE_DB_URL,
projectId: process.env.FIREBASE_PROJECT_ID,
storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.FIREBASE_MESSAGE_SENDER_ID
}
: {}
...
export const actions = {
nuxtServerInit({ commit, state, store, dispatch }, { req }) {
if (process.server) {
commit('setSharedEnv', getSharedEnv())
}
}
}
plugins/firebase.js
import Vue from 'vue'
import firebase from 'firebase/app'
Vue.use(firebase)
export default context => {
// perform a store action manually to have access to `sharedEnv` object
context.store.dispatch('nuxtServerInit', context)
const env = { ...context.store.state.sharedEnv }
if (!firebase.apps.length) {
console.log('initialize firebase...')
firebase.initializeApp(env)
}
return firebase
}
pages/login/index.vue
<script>
import firebase from '#/plugins/firebase'
export default {
name: 'login',
data() {
return {
email: '',
password: ''
}
},
methods: {
login: function() {
let additionalClaims = {
premiumAccount: true
}
console.log('login page')
console.log(firebase)
firebase
.auth()
.signInWithEmailAndPassword(this.email, this.password)
.then(
response => {
...
You need to also import the firebase/auth library if you need the auth feature
i.e.
import firebase from 'firebase/app';
import 'firebase/auth';

How to Add Firebase Firestore Data into SSR Nuxt Apps Vuex Store

I'm trying to set locations into a Vuex store in my Nuxt app. I've looked into using vuexfire, however, I'm unsure if this would be optimal in a SSR app or generally what is the most simple best practice.
How do you request from firebase firestore and set the state (of the 'locations' in this example)?
Would it be best to use nuxtServerInit in a SSR app?
store/index.js
import Vuex from 'vuex'
import firebase, {auth, db} from '#/services/firebaseinit.js'
const createStore = () => {
return new Vuex.Store({
state: {
user: null,
locations: [],
},
getters: {
// User
activeUser: (state) => {
return state.user
},
// Locations
loadedLocations(state) {
return state.loadedLocations
}
},
mutations: {
// User
setUser (state, payload) {
state.user = payload
},
// Locations
setLocations (state, locations) {
state.locations = locations
}
},
actions: {
// Locations
setLocations(vuexContext, locations) {
vuexContext.commit('setLocations', locations)
},
// Users
autoSignIn ({commit}, payload) {
commit('setUser', payload)
},
signInWithFacebook ({commit}) {
return new Promise((resolve, reject) => {
auth.signInWithPopup(new firebase.auth.FacebookAuthProvider())
resolve()
})
},
signOut ({commit}) {
auth.signOut().then(() => {
commit('setUser', null)
}).catch(error => console.log(error))
},
}
})
}
I haven't used vuexfire but have used firebase with nuxt and it works pretty well. this is what I did.
npm install --save firebase
create a file called firebase.js and put this sort of code in it:
import * as firebase from 'firebase'
if (!firebase.apps.length) {
firebase.initializeApp({
apiKey: '<your-api-key>',
authDomain: '<your-domain>',
databaseURL: '<your-url>',
projectId: '<your-id>',
storageBucket: '<your-bucket>'
})
}
export { firebase }
then you register that file as a plugin in nuxt.config.js
plugins: [
'#plugins/firebase.js'
],
You need to import firebase at the top of your index.js (or other file you're using it in) in the store.
import * as firebase from 'firebase'
then you can use firebase in your nuxtServerInit as you want. Eg.
actions: {
nuxtServerInit({dispatch}, context) {
return Promise.all([
dispatch('get_posts', context),
dispatch('any_other_actions', context)
]);
},
get_posts (vuexContext, context) {
return firebase.database().ref(YOUR DB).once('value')
.then(res => {
//...What you want it to do here
})
},
Firebase is pretty powerful and you'll want to read the docs for specifics about the functions you want to perform but yeah, goes good in nuxt.

Resources