Intro
In this blog I will share some thoughts about my experience building an Express API with TypeScript using Firebase. I'll go over why I chose Firebase for my project, pros and cons I noticed while using it, and my overall review of my development experience.
The API I was building was for red ink, a platform to connect writers and editors with specific subject matter expertise.
I built the first version of red ink (both frontend and backend) in ten days. The bulk of the API development occurred during the first three days of the build.
Why Firebase?
I initially chose to build with Firebase primarily because of its authentication module. Firebase Authentication offers multiple methods for creating an account, including GMail, Facebook, and Twitter, so it was an ideal solution. An editing platform is not useful without editors, so making it as easy as possible to get editors on board was a key concern of mine.
Given that I was using Firebase Authentication, I thought that using Firestore (Firebase's NoSQL database solution would allow for easy integration of the user data provided by Firebase Authentication, although I learned a full day into my project that this is not the case. Even though there is no intrinsic link between Firebase Authentication and Firestore, it's pretty simple to combine the two.
Functionality of my TypeScript + Express API
The API I built is fairly basic for now. It allows a user to send requests to Create, Read, Update and Delete data from the Firestore database, and also has some routes for sending email notifications to users when certain events occur in the app.
I did not technically need to create an Express server for my app, since Firebase allows you to make calls straight to Firestore from the browser, but I chose to include one in my project for two reasons: to hide API keys used for the email feature of my app, and because I wanted to manipulate the data sent back from Firestore before using it on my frontend.
Pros of building an Express API as a Firebase project
Easy configuration and Deployment
Firebase has a great command line interface that makes it easy to initialize your project and get it deployed quickly. This makes it easy to ensure that the code you write in development will also work in production.
I have had problems in the past with deploying TypeScript APIs to Heroku that have led required lots of Stack Overflow searches and tinkering with the ts-config file to resolve. This was not the case with Firebase at all. Firebase provides a standard ts-config file that required no changes for my project. There are few things more frustrating to me than wasting time on configuration and deployment at the start of a project, especially when working on a tight timeline.
Documentation, Tutorials, and the Community
Firebase has a very thorough documentation, and a great set of tutorials for pretty much everything on the platform. The Google Developer Advocates that lead the tutorials are great communicators and the videos have very high production quality. The series on data modeling for Firestore was particularly useful during this project when designing my database.
Though Firestore is a NoSQL database and very similar to MongoDB (with which I've worked many times), there are some differences with how Firestore and MongoDB perform queries that may effect how you model your data for some projects. The Firestore data modeling series provides many realistic examples for how to model data effectively, which was extremely helpful.
In addition to the Google documentation and Tutorials, there is a vibrant community of Firebase users online, many of whom create tutorials on YouTube and write blogs about common Firebase use cases and problems. Given that not all of the Google videos are up to date with the latest versions of various Firebase products, these can come in handy.
Ease of adding in new tools incrementally
Firebase offers many products -- not just Authentication and a NoSQL database. It can be used for anything from hosting a static site to building a full-fledged web app equipped with analytics that incorporates machine learning. Integrating new tools as they become needed in your app is straightforward and only requires a few changes to your configuration.
I plan on adding cloud storage to red ink in my next sprint in order to allow editors to upload profile photos, pdfs, and word documents to the app with the help of this video.
Cons of building an Express API as a Firebase project
Workflow
When building an Express API on Firebase, your controllers will be used to call cloud functions. Whenever you write make a change to your API you need to deploy your cloud functions again in order for those changes take place. This can take anywhere from 1-3 minutes each time and can seriously slow down your development process. An Express API without cloud functions is much faster to iterate on, even with a database deployed via Heroku. If you plan on building an Express API as a Firebase project, I definitely recommend using TypeScript over JavaScript as it will help you catch errors more quickly which can reduce the amount of times you have to deploy your cloud functions and wait a few minutes to test them.
There may be solutions or workarounds to reduce the amount of time you spend waiting for deployments, but I was unable to find any that worked for me during this 10 day sprint. Please let me know if I'm missing something obvious!
Firestore is not always developer-friendly
When it comes to NoSQL databases, Firestore is pretty good and can get the job done for basic applications, but it is not as robust as MongoDB and can be harder to work with at times.
One example from red ink of how working with Mongoose + MongoDB is easier than working with Firestore is when attempting to create or update multiple documents at once. Mongoose makes it incredibly easy to create or update multiple documents at once, but Firestore requires that you use batching and a loop in order to create multiple documents at once.
While I'm not sure which option is more efficient under the hood, the code required for creating and updating multiple documents at once with MongoDB is much simpler than the code used for the exact same operations with Firestore.
Here's a microcosmic example of how much simpler it can be to work with Mongoose + MongoDB than Firestore
//// Mongoose + MongoDB ////
const createManyDocumentsMongo = async (req: Express.request, res: Express.response) : void => {
try {
const data: SomeInterface[] = req.body
const created = await db.create(data)
// MongoDB returns the newly created data from the .create method if data successfully added to db
res.status(201).json({status: 201, message: 'created new documents from array', data: created})
} catch (error) {
console.log(error)
res.status(400).json({status: 400, message: 'error trying to create new documents from array'})
}
}
//// Firestore ////
const createManyDocumentsFirestore = async (req: Express.request, res: Express.response) : void => {
try {
const dataArray: SomeInterface[] = req.body
const batch = db.batch()
dataArray.forEach((object) => {
const newDoc = db.collection('someCollection').doc()
await newDoc.set(object)
})
batch.commit()
// Firestore does not return the newly created data from the .set method if data successfully added to db
// In this instance, we're just sending back the dataArray
res.status(201).json({status: 201, message: 'created new documents from array', data: dataArray})
} catch (error) {
console.log(error)
res.status(400).json({status: 400, message: 'error trying to create new documents from array'})
}
}
Conclusion
Overall, I enjoyed working with Firebase. Despite its flaws, the ease of getting up and running quickly and the documentation make me likely to use Firebase again for small projects.
I'm very happy with my decision to use Firebase for red ink because I had a limited amount of time to build a prototype and the API's requirements were not very complex. I may end up replacing elements of my backend in the future if I spend a lot of time improving red ink, but for now most of the planned improvements are on the frontend so I will stick with Firebase and Firestore.
If you have any questions about building an Express API as a Firebase project, or feel I have missed anything in this article, please reach out to me via Twitter or through my personal site.
Top comments (3)
This article provides valuable insights. However, for the purpose of development, an alternative option is to utilize the Firebase Emulator. With the emulator, you can instantly load your changes, much like a regular Express server. This eliminates the need for repetitive deployment of your cloud functions during the development process, allowing for a more efficient workflow.
Loved this article. What tooling/framework did you use on the front end? And legit business idea!
Thanks Mike!! I’m using React and Scss for the frontend, hosted on Netlify