Building a People API for a growing platform

How a remote team built a new API from scratch using Finale REST

Renzo Rozza
Apolitical Engineering
5 min readDec 15, 2020

--

When I took a job at Apolitical, a fast-growing global learning platform for public servants, it was the first time I joined a company remotely.

As you might imagine, it was challenging: new teammates who you only see on a Zoom window, few opportunities to socialise outside of working hours, etc, etc. But, as I had expected, there was little time to dilly-dally, anyway. We found ourselves trying to overcome performance issues with the old API and the first project I was given involved migrating the entire user base from WordPress to a new, modern, and ready-to-scale API.

TL;DR: If you’re cherry-picking modules for your next Node.js project and you want to jump straight into your business logic, then use Finale REST endpoints and controllers from Sequelize models in your Express.js app to allow you to create a powerful and customisable API.

Yes, I know, another blog post about REST APIs and microservices — please, just bear with me to find out how to quickly prototype your next project.

Image from @SimpsonsOps

Getting started

Where the tech stack was concerned, the project had some preconditions:

  • On the development side, we planned to use PostgreSQL relational database, Node.js (Javascript ECMAScript 2018) runtime, Sequelize object-relational mapping (ORM), and Express.js server
  • On the infrastructure side, we run our platform on Google Cloud Platform (GCP) with Google Kubernetes Engine (GKE) and Cloud SQL

Of course, all of these are industry standards and well-known technologies. Apart from the software architecture and database schema itself, the complexity of the project relied upon structuring the REST endpoints and controllers.

We needed to do this in a way that allowed us to maintain and extend the business logic of our resources. That’s when Finale REST came into action to offer CRUD (create, read, update, and delete) operations out-of-the-box, significantly reducing the effort and amount of code needed for the initial setup.

Proof of Concept

The first step of any successful project is to validate the modules (or 3rd party dependencies) that will satisfy your needs. To get us started, we decided to set up a basic user resource to get a real sense of what the value would be from using Finale REST on our API stack. The code would have looked like this:

Note: The Express.js middlewares (e.g. bodyParser) should be set before the Finale REST initialisation — otherwise the POST or PUT methods won’t work (line 34).

To our pleasant surprise, at that point, we had working REST endpoints and controllers for the user resource, including CRUD operations and support for filtering, searching, sorting, and pagination (to find more about this, visit this page).

Milestones

Now, even on the best days, your API will require more business logic than plain REST controllers. Perhaps, you may need to secure your endpoints with JSON Web Tokens (JWT), or you may need to write presentation layers based on roles and permissions, or any other functionality you may think of.

To do this, Finale REST has built-in support for milestones. Basically, each controller has hooks for setting and overriding behaviour at each step of the request. Or, in other words, the milestones provide opportunities to run your business logic at various important steps throughout the duration of the request (to find more about this, visit this page). An example of how to use milestones can look like this:

Note: The userResource variable was previously defined (line 41).

The context object must be used to control the milestone flow, allowing you to continue, skip or stop the milestones chain, or directly throw an error from your milestones. The example above is only setting milestones for some of the hooks, but you are able to dig further into changing any other step on the CRUD operations. Finale REST also comes with very handy, predefined errors (Not Found, Bad Request, Forbidden).

Conclusions

Currently, you can find many modern web-frameworks for creating Node.js microservices out there, such as LoopBack, Nest.js, or Feathers, to mention only a few. And if you’re developing an API from scratch, it could be a good idea to go with one of those. But, given our preconditions, it was clear for us that having a highly customisable plain Express.js server was the way to go — and I would not be suggesting using Finale REST if the People API had not successfully gone live. You can trust me that the People API is handling all the requests related to the users on the Apolitical platform.

However, the engineering team found Finale REST somewhat difficult to get started with. The main reason, in my experience, is that it is unclear which functionalities are built-in, and which are not. I have been asked multiple times, “but… where’s the query to the database?” or similar questions. And the answer is: Finale REST does that for you! Despite this disadvantage, the flexibility of adding business logic at any point of the request/response flow is one of the things Finale REST has implemented very well, and it has allowed us to quickly iterate and increment the functionality of the People API over time.

During this project, I had the opportunity to meet and become part of the incredible engineering team at Apolitical, where we share the motivation and commitment to Apolitical’s mission of creating great opportunities to learn for public servants everywhere.

--

--