Let's try Firebase

In a nutshell, Firebase is an ecosystem of Google tools that can be used to build full-stack applications.
It’s categorized as a backend-as-a-service (or BaaS) which gives developers the opportunity to create applications without the hassle of setting up the backend.
Key features- Authentication
- Cloud Firestore
- Realtime Database
- Storage
- Hosting
- Cloud Functions
- Machine learning
During my research, I created a chat app that utilizes a few of Firebase’s main features.
https://react-firebase-poc-1c7c7.web.app
First, you have to log in to the Firebase console, create a project, and add Firebase to your app.
https://console.firebase.google.com/
At that point, you should receive credentials that will let you connect Firebase with your app.
firebase.js
import firebase from 'firebase';
const config = {
apiKey: 'AIzaSyCNH_Y_8CyucgHOas4EPxSWX4to3tqj7fdA2sI',
authDomain: 'react-firebase-poc-1c7c7.firebaseapp.com',
databaseURL: 'https://react-firebase-poc-1c7c7.firebaseio.com',
projectId: 'react-firebase-poc-1c7c7',
storageBucket: 'react-firebase-poc-1c7c7.appspot.com',
messagingSenderId: '22747307388',
appId: '1:22747307388:web:7f1bgasd827487805fa48118f9',
measurementId: 'G-35J1425GSF02',
};
firebase.initializeApp(config);
export default firebase;
Authentication
Documentation: https://firebase.google.com/docs/auth/web/start
Once we have our app initialised, we can move on. Firebase offers plenty of sign-in methods. We will use three of them in our chat app.
Before you start coding, you have to navigate to the authentication tab in the Firebase console and enable the methods you want to use.
authentication.js
import firebase from './firebase';
const auth = firebase.auth();
const googleProvider = new firebase.auth.GoogleAuthProvider();
const githubProvider = new firebase.auth.GithubAuthProvider();
export const signInWith = (provider) => async () =>
auth.signInWithPopup(provider).then((data) => {
const user = {
id: data.user.uid,
email: data.user.email,
isVerified: data.user.emailVerified,
};
return user;
});
export const signInWithGoogle = signInWith(googleProvider);
export const signInWithGithub = signInWith(githubProvider);
export const signOut = async () => auth.signOut();
export const signUpWithEmailAndPassowrd = async ({ email, password }) =>
auth.createUserWithEmailAndPassword(email, password).then((data) => ({
id: data.user.uid,
email: data.user.email,
isVerified: data.user.emailVerified,
}));
export const signInWithEmailAndPassowrd = async ({ email, password }) =>
auth.signInWithEmailAndPassword(email, password).then((data) => ({
id: data.user.uid,
email: data.user.email,
isVerified: data.user.emailVerified,
}));
export const verifyAuth = async (fn) => firebase.auth().onAuthStateChanged(user => {
if(user) {
// user logged in
} else {
/// user logged out
}
});
The authentication methods are very straightforward.
The signInWithPopup method takes the provider as an argument and returns some information from, for example, your Google account. In addition, you receive an access token, data.credential.accessToken, that will let you access more info from the Google API or other services.
onAuthStateChanged lets you check whether the user has an active session.
Storage
Documentation: https://firebase.google.com/docs/storage/web/start
Cloud Storage lets you upload and share user-generated content, such as images and video, which allows you to build rich media content into your apps.
In our chat app, we use it to store pictures uploaded by users.
storage.js
import firebase from './firebase';
const storage = firebase.storage();
export const uploadImage = async (image) => {
const name = image.name + Date.now();
const ref = storage.ref(`images/${name}`);
await ref.put(image);
const url = await ref.getDownloadURL();
return url;
};
storage.ref(`images/${name}`); creates the reference to the resource;
ref.put(image); uploads the image to the storage
await ref.getDownloadURL(); and finally, we can get a URL to the specific resource;
Firestore
Documentation: https://firebase.google.com/docs/firestore/quickstart
Cloud Firestore stores data in documents, which are stored in collections. Cloud Firestore creates collections and documents implicitly the first time you add data to the document. You do not need to explicitly create collections or documents.
If you’re not sure whether you should use Cloud Firestore or Realtime Database, check this survey → https://firebase.google.com/docs/database/rtdb-vs-firestore
Our app needs to store users and messages, so let's create a few functions that will let us create and retrieve this data.
firestore.js
import firebase from './firebase';
import * as storage from './storage';
const db = firebase.firestore();
export const createUser = async ({ id, email, isVerified }) =>
db.collection('users').doc(id).set({
id,
email,
isVerified,
});
export const createUserIfNotExist = async ({ id, email, isVerified }) =>
db
.collection('users')
.doc(id)
.get()
.then(async (doc) => {
if (doc.exists) {
return doc.data();
} else {
const user = await createUser({ id, email, isVerified });
return user;
}
});
export const createMessage = async ({ text, file, authorId }) => {
if (file) {
const url = await storage.uploadImage(file);
db.collection('messages').add({
value: url,
type: 'img',
authorId,
created: firebase.firestore.Timestamp.fromDate(new Date()),
});
}
if (text) {
db.collection('messages').add({
value: text,
type: 'text',
authorId,
created: firebase.firestore.Timestamp.fromDate(new Date()),
});
}
};
db.collection('users').doc(id).set({...}) creates a new document with a specified id in users collenction.
db.collection('messages').add({...}) also, you can let firebase to generate id for you.
firestore.js
...
export const listenForMessages = async (fn) =>
db
.collection('messages')
.onSnapshot(async (snapshot) => {
let newMessages = [];
snapshot.docChanges().forEach(function (change) {
if (change.type === 'added' || change.type === 'modified') {
newMessages.push({ id: change.doc.id, ...change.doc.data() });
}
});
...
});
Since we are building a chat, we need to set up a listener that will inform us about every change in the message collection. With Firestore, you can listen to a document with the onSnapshot() method. In our case, we listen only for new and updated messages.
More info:https://firebase.google.com/docs/firestore/query-data/listen
Cloud Functions
Documentation:https://firebase.google.com/docs/functions/get-started
Cloud Functions is a serverless framework that lets you automatically run backend code in response to events triggered by Firebase features and HTTPS requests. Your code is stored in Google's cloud and runs in a managed environment.
We will use this feature to moderate messages sent by users.
Let’s jump to a terminal for a minute. Execute:
firebase init
and select Functions.
After that command, you should have created a functions folder with index.js inside.
A cloud function lets us listen to changes in the Firestore message collection and run some code on every change. In our case, we want to check every new message, so we should use the onCreate method.
If the message contains a swear word, we moderate it and save the updated version.
functions/index.js
...
exports.moderator = functions.firestore
.document('messages/{messageId}')
.onCreate((snap) => {
const message = snap.data();
if (message && message.type === 'text') {
const moderatedMessage = moderateMessage(message.value);
console.log(
'Message has been moderated. Saving to DB: ',
moderatedMessage
);
return snap.ref.update({
value: moderatedMessage,
moderated: message.text !== moderatedMessage,
});
}
return null;
});
...
Hosting
With Firebase, we can host the app using a few commands in the terminal.
Make sure you have installed firebase-tools globally.
npm install -g firebase-tools
If you’re not logged in, do it with the command firebase login and select a project.
First, we have to build our app:
yarn build
Next, run:
firebase init
Choose your hosting:
firebase serve --only hosting
firebase deploy
And voilà, you should see a hosting URL in the terminal.
Repo→ https://github.com/LukeWlodarczyk/react-firebase-poc
Check out my app→ https://react-firebase-poc-1c7c7.web.app