im looking to retrieve data from the firestore.first it worked well when i ejected from expo i cant able to retrieve data from the servers. when i read some documentation they suggested to use
let myApp = initializeApp(firebaseConfig);
myApp.firestore().settings({ experimentsalForceLongPolling: true });
const firestore = getFirestore(myApp);
but im ettin error myApp.firestore() is not a function.
here is my code:
import { initializeApp } from "firebase/app";
const firebaseConfig = {
};
let myApp = initializeApp(firebaseConfig);
myApp.firestore().settings({ experimentsalForceLongPolling: true });
const firestore = getFirestore(myApp);
im thinking there is a problem in import can someone help me please
The settings to enable experimentalAutoDetectLongPolling should be enabled through initializeFirestore there you will find settings: FirestoreSettings argument refer FirestoreSettings which you can set as follows :
import { initializeApp } from "firebase/app";
import { initializeFirestore, getFirestore } from "firebase/firestore";
const firebaseConfig = {
};
let app = initializeApp(firebaseConfig);
let db;
try {
db = initializeFirestore(app, { experimentalAutoDetectLongPolling: true }); // <= settings
} catch (e) {
if (e.code === 'failed-precondition') {
// Multiple app instances detected
db = getFirestore(app);
} else {
throw e;
}
}
And as initializeFirestore is equivalent to getFirestore method so no need to reinitialize firestore again as shown in docs:
Initializes a new instance of Firestore with the provided settings. Can only be called before any other function, including (getFirestore:1). If the custom settings are empty, this function is equivalent to calling (getFirestore:1).
Related
I have this multi layered application entirely hosted on GCP. At the moment, we only have the back-end part. Front-end and API are to be developed. For the front-end, the decision has been made - it will be a React.js app hosted on Firebase Hosting and the authentication method will be Email/password and users will be provisioned manually through the Firebase Hosting UI.
As we'd like to have a re-usable middle layer (API) we're in a process of making a decision what type of a solution to be used for our middle layer. The main request here is only logged in users to be able to call the API endpoints. Eventually, there will be also a native/mobile application which will have to also be able to make authenticated requests to the API.
My question here is, what type of GCP service is advised to pick here? I want it to be light, scalable and price optimized. Preferred programming language would be C# but Node.js would be also acceptable.
Firebase Functions would work well for this authenticated API. With a function, you can simply check for the existence of context.auth.uid before proceeding with the API call.
https://firebase.google.com/docs/functions/callable
You'll want to use the .onCall() method to access this context.auth object.
Here's an example I took from one of my active Firebase projects which uses this concept:
Inside your functions>src folder, create a new function doAuthenticatedThing.ts
/**
* A Firebase Function that can be called from your React Firebase client UI
*/
import * as functions from 'firebase-functions';
import { initializeApp } from 'firebase/app';
import { connectFirestoreEmulator, getFirestore, getDocs, query, where, collection } from 'firebase/firestore';
import firebaseConfig from './firebase-config.json';
let isEmulator = false;
const doAuthenticatedThing = functions
.region('us-west1')
.runWith({
enforceAppCheck: true,
memory: '256MB',
})
.https.onCall(async (_data, context) => {
// disable if you don't use app-check verify (you probably should)
if (context.app == undefined) {
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called from an App Check verified app.',
);
}
// checks for a firebase authenticated frontend user
if (context.auth == undefined) {
throw new functions.https.HttpsError(
'failed-precondition',
'The user must be authenticated.',
);
}
// establish firestore db for queries
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
// start the emulator
if (process.env.MODE === 'development' && !isEmulator) {
connectFirestoreEmulator(db, '127.0.0.1', 6060);
isEmulator = true;
}
// obtain the user's firebase auth UID
const uuid = context?.auth?.uid as string;
// do some database stuff
const ref = collection(db, 'collection-name');
const q = query(ref, where(uuid, '==', uuid));
const results = await getDocs(q);
if (results.empty) {
throw new functions.https.HttpsError(
'internal',
'There were no results found!',
);
}
// prepare document data
const data: Array<any> = [];
// gather chats, and an array of all chat uids
results.forEach((d) => {
data.push({ id: d.id, data: d.data() });
});
return data;
});
export default doAuthenticatedThing;
Make sure to reference this new Firebase Function in the functions/src/index.ts file.
import doAuthenticatedThingFn from './doAuthenticatedThing';
export const doAuthenticatedThing = doAuthenticatedThingFn;
Create a frontend React Hook so any component can use any function you make. Call it useGetFunction.ts
import { getApp } from 'firebase/app';
import { getFunctions, HttpsCallable, httpsCallable } from '#firebase/functions';
const useGetFunction = (functionName: string): HttpsCallable<unknown, unknown> => {
const app = getApp();
const region = 'us-west1';
const functions = getFunctions(app, region);
return httpsCallable(functions, functionName);
};
export default useGetFunction;
Now you can simply get this function and use it in any React component:
const SomeComponent = () => {
const doAuthenticatedThing = useGetFunction('doAuthenticatedThing');
useEffect(() => {
(async () => {
const results = await doAuthenticatedThing();
})();
}, []);
};
I am trying to trigger cloud functions from firestore events (onWrite) but I don't find the correct way to implement it with the version 9 modular that I am using for this project. The whole documentation is with version 8 (named space).
Here is what I am trying to do (version 8) :
export const documentWriteListener = functions.firestore
.document('collection/{documentUid}')
.onWrite((change, context) => {
if (!change.before.exists) {
// New document Created : add one to count
db.doc(docRef).update({ numberOfDocs: FieldValue.increment(1) });
} else if (change.before.exists && change.after.exists) {
// Updating existing document : Do nothing
} else if (!change.after.exists) {
// Deleting document : subtract one from count
db.doc(docRef).update({ numberOfDocs: FieldValue.increment(-1) });
}
return;
});
Here is my version 9 firebase initialization file :
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getAuth } from "firebase/auth";
import { getFunctions } from "firebase/functions"
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const auth = getAuth(app);
const functions = getFunctions(app);
export { db, auth, functions }
and here is what I've tried for the cloud function (that I put in an independent file actionsCount.js) :
import { db, functions } from '../../firebase/initFirebase';
import { updateDoc, doc } from "firebase/firestore";
import * as functions from 'firebase-functions';
export const documentWriteListeners = functions.firestore
.document('actions/{documentUid}')
.onWrite((change, context) => {
const actionsCounter = doc(db, "actionsCount", "counter")
if (!change.before.exists()) {
// New document Created : add one to count
await updateDoc(actionsCounter, { numberOfDocs: FieldValue.increment(1) });
} else if (change.before.exists() && change.after.exists()) {
// Updating existing document : Do nothing
} else if (!change.after.exists()) {
// Deleting document : subtract one from count
await updateDoc(actionsCounter, { numberOfDocs: FieldValue.increment(-1) });
}
return;
})
When I deploy using firebase deploy --only functions, I get the error : Cannot understand what targets to deploy/serve. No targets in firebase.json match '--only functions'.
Should I put the function somewhere else ? Function is wrong ?
Thanks a lot for your help !
You need to initialize Firebase Functions with the command firebase init. When you select functions and proceed with the setup, it'll create a new functions directory containing an index.js/ts file by default. That's where you add your Cloud Functions.
The firebase-functions SDK is not meant to be used on client side.
The directory structure would look like this:
firebase deploy --only functions will deploy the functions.
Finally fixed this! Half a day haha
So I obviously ran the functions firebase init as suggested by Dharmaraj.
As per the modular (version 9), it looks like we can do it. So I basically tried to initialize the firebase sdk in the functions/index.js file with the version 8 (named-space) methods and it worked.
Here is the code :
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
const fieldValue = admin.firestore.FieldValue;
// Updating the Actions document count
exports.documentWriteListeners = functions.firestore.document('actions/{documentUid}').onWrite((change, context) => {
if (!change.before.exists) {
// New document Created : add one to count
db.doc('actionsCount/counter').update({ numberOfDocs: fieldValue.increment(1) });
} else if (change.before.exists && change.after.exists) {
// Updating existing document : Do nothing
} else if (!change.after.exists) {
// Deleting document : subtract one from count
db.doc('actionsCount/counter').update({ numberOfDocs: fieldValue.increment(-1) });
}
return;
})
I want to upload an image to firebase storage, version 9. I have working code for the firestore, but I cant for the life of me understand the firebase docs regarding uploading, and how to make it work for Vue (which also requires the import of a REF function).
my question is: How do I import the ref function in Vue and also import and use the ref function from firebase firestore?
This is what I have. It feels wrong to wrap the Firebase ref with a .value, but I just put it in there to get past the vue error.
vue component code fragment: <-- this works
if (imageFile.value) {
await uploadImage(imageFile.value);
console.log("image:" + url.value);
}
useStorage.js <--this is where everything breaks down trying to convert from Firebase 8 to 9. Is it the vue Ref function?
import { ref } from "vue";
import { projectStorage } from "../firebase/config";
import { uploadBytesResumable, getDownloadURL } from
"#firebase/storage";
const useStorage = () => {
const error = ref(null);
const url = ref(null);
const filePath = ref(null);
//I need to use ref with firestore here
const uploadImage = async (file) => {
filePath.value = `images/${file.name}`;
const storageRef = ref(projectStorage,
filePath.value).value;
try {
const res = await storageRef.put(file);
url.value = res.ref.getDownloadURL();
} catch (err) {
console.log(err.message);
error.value = err.message;
}
};
return { url, filePath, error, uploadImage };
};
export default useStorage;
config.js
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getStorage } from "firebase/storage";
import { getAuth } from "firebase/auth";
const firebaseConfig = {
[info]
};
// init firebase
const firebaseApp = initializeApp(firebaseConfig);
// init firestore service
const db = getFirestore(firebaseApp);
// init firestore authorization
const auth = getAuth(firebaseApp);
const projectStorage = getStorage(firebaseApp);
export { db, projectStorage, auth };
You can set an alias for either of the imports as shown below:
import { ref } from "vue";
import { projectStorage } from "../firebase/config";
import { ref as storageRef } from "#firebase/storage";
const fileRef = storageRef(projectStorage, filePath.value);
// use storageRef here ^^^ instead of ref from vue
Also checkout: How to import two classes by the same name in javascript/es6?
The following code works, and I get an error back if there's an issue.
Note, this is vue code. Hence the .value
import { getAuth, createUserWithEmailAndPassword } from 'firebase/auth'
const register = async () => {
loading.value = true
let response
try {
const auth = getAuth()
response = await createUserWithEmailAndPassword(
auth,
form.value.email,
form.value.password
)
} catch (err) {
console.log(err.message)
}
loading.value = false
return response
}
However, here's an example of what error.message returns:
Firebase: Password should be at least 6 characters (auth/weak-password).
My question. Is there a way to get a clean message back? By that, I mean without Firebase: and (auth/weak-password).
Or am I missing something here? Is there another way I'm supposed to deal with Firebases error object? Perhaps I'm supposed to take the error.code and write a custom message myself for every scenario?
Let me know if any other information is needed, and I'll update the question :)
I'm currently using helper function, but don't think it's the best solution. Is there any better one?
function getRefinedFirebaseAuthErrorMessage(errorMesssage: string): string {
return errorMesssage
.replace('Firebase: ', '')
.replace(/\(auth.*\)\.?/, '');
}
Notice that to force Firebase 9 to return an error message as Firebase: {real, descriptive error message}. (auth/{code}). it is necessary to init it with errorMap option set to debugErrorMap:
import { FirebaseApp, initializeApp } from 'firebase/app';
import { Auth, initializeAuth, debugErrorMap } from 'firebase/auth';
const app: FirebaseApp = initializeApp(firebaseConfig);
const auth: Auth = initializeAuth(app, { errorMap: debugErrorMap });
Otherwise, Firebase will return only error codes.
import { getAuth, createUserWithEmailAndPassword } from 'firebase/auth'
const register = async () => {
loading.value = true
let response
try {
if(form.value.password.length <= 6 ){
return "Password should be at least 6 characters (auth/weak-password)"
}
const auth = getAuth()
response = await createUserWithEmailAndPassword(
auth,
form.value.email,
form.value.password
)
} catch (err) {
console.log(err.message)
}
loading.value = false
return response
}
I'm trying to use google sign using firebase in the Vue framework. I don't know what the error is this can anyone help me with this.
vue.runtime.esm.js?2b0e:1888 TypeError: _firebase_js__WEBPACK_IMPORTED_MODULE_2__.fb.auth.GoogleAuthProvider is not a constructor
at VueComponent.socialLogin (Signin.vue?3d55:76)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at HTMLButtonElement.invoker (vue.runtime.esm.js?2b0e:2179)
at HTMLButtonElement.original._wrapper (vue.runtime.esm.js?2b0e:6917)
this is my code
firebase.js
import firebase from "firebase";
var firebaseConfig = {
config
};
const fb=firebase.initializeApp(firebaseConfig);
export { fb };
Sign in.vue
<script>
import { fb } from "../firebase.js";
export default {
name: "Signin",
components: {},
data() {
return {
};
},
methods: {
socialLogin() {
const provider = new fb.auth.GoogleAuthProvider();
fb.auth().signInWithPopup(provider).then((result) => {
this.$router.replace('home');
}).catch((err) => {
alert('Oops. ' + err.message)
});
}
}
};
</script>
The auth property (not the auth() function) is available on the static firebase object, not your firebase app.
You want something more like this
import firebase from "firebase/app"
import "firebase/auth" // 👈 this could also be in your `firebase.js` file
const provider = new firebase.auth.GoogleAuthProvider()