Etna π- A Nodejs boilerplate for building RESTful API
Before I introduce Etna lets discuss a bit about what motivated me to create this boilerplate and a bit of background on how I got to the point of creating this boilerplate.I have been working with and building a lot of Nodejs related applications & API's over the years.What I have been noticing most of the time was that most boilerplates or projects I came across rarely used SQL/relational databases as the underlying database. I think this was partly because a couple of years ago most nodejs drivers for mysql was really buggy and a bit inconsistent in performance compared to existing drivers for most to other languages and frameworks. This coupled with the undeniable trend towards NoSQL over the last few years probably had something to do with the slow adoption rate towards SQL in the nodejs community. However today most drivers are battle tested, well established and relatively consistent. Despite that fact when I wanted to try and make an API using MySQL I was rather surprised as I couldn't find a proper boilerplate that I could use comfortably and easily without much hassle. Most boilerplates included the basic mysql driver/npm module. Which was good enough and got the job done, but also meant that you manually had to write most of the SQL yourself.This usually ended up with most boilerplates having tight coupling between persistence layer and models/API. This lead me down a path of searching for something with a little more abstraction to the underlying database however could hardly find any that matched my needs. So I was left with no option but to try and create my own boilerplate, this I didn't want to start from scratch or reinvent the wheel so I went ahead and did some searching for a bare bones boilerplate that at least had Nodejs , Typescript & a API framework used. I then came across Matterhorn which is exactly that and seemed quite simple and solid. So I decided to build my boilerplate on top of it reworking some of its structure and adding more features.
Thanks to Matterhorn ποΈ Etna had a solid foundation to be built on. Along with the key features of Matterhorn, Etna offers you more while being adamant on simplicity and ease of use.
Etna is built built with :
Etna adds several abstraction layers and allows easy integration of any of the following databases:
Etna is opinionated and will only support these databases.If you want support for NoSQL databases Etna may not be the boilerplate you were looking for. Etna uses an ORM(Objectionjs) to support these databases which allows you to add models that represent a database table or an instance of the model which represents a table row. A model could be as simple as this(or complex as you want it to be) :
import { Model } from "objection";
class Candidate extends Model {
readonly id!: number;
firstName!: string;
lastName!: string;
contactNumber!: string;
address?: string;
createdAt?: Date;
updatedAt?: Date;
static get tableName() {
return "candidate";
}
}
The only requirement for a Model is that the static method static get tableName()
is provided and returns the name of the table the model relates to. You could also add any kind of complex relationships between models using relationMappings()
which you can read more about on (Objection.js guide). Once a model is created querying is made as simple as it can get, for example :
import { Candidate } from "../models";
const candidatesWithDistinctNames = await Candidate.query().distinct("firstName");
The above query resolves to
select distinct `firstName` from `candidate`
You can read more about it on Knex which is the underlying query builder for Etna so any type of complex query could easily be made with much ease with static typing !
For the API framework Etna relies on Fastify which claims to have 2x the performance of Express! Fastify also offers a simple API while still not compromising any core functionalities. And most of its additional features / functionality is offered in the form of plugins and some of these plugins are built onto Etna Swagger , Auth & CORS which you can remove if not needed with much ease. Its quite easy to adopt to specially if you come from an Express background.
Etna also allows you to write unit tests using Jest. And writing an API test is simple as this
import createServer from "../../../src/server";
const fastify = createServer();
test("Test if Get /api/candidates returns a 200 with a payload", async () => {
const response = await fastify.inject({
method: "GET",
url: "/api/candidates"
});
expect(response.statusCode).toBe(200);
expect(Array.isArray(JSON.parse(response.payload))).toBeTruthy();
});
most of the configurations and setup for it has been done for you all you have to do is just get started right away !. You can run the tests using
npm run test
π jest
π migrations
π src
|--π database
|-- π connect
|-- π index
|--π models
|-- π modelName
|-- index
|--π plugins
|--π routes
|-- π routePathName
|-- π index
|-- π handler
|-- π index
|-- π server
πtests
|--π routes
|-- π routePathName
|-- π index
|-- π handler
To explain a bit about the project structure the π src
is where most of your code would be. Its divided into 4 sub-folders :
π database -
π index
.π models -
π plugins -
π routes -
π plugins
where each major route is plugged on.π index and π server -
The π tests tests folder replicates the same structure on π routes which should ideally unit test everything used on a routes. The π migrations folder contains the logic to add or create the initial tables / database structure when initializing. It also contains the logic to remove tables related to the application when needed.
π―ββοΈ Clone it to your computer
git clone https://github.com/DasithKuruppu/etna.git
cd etna
npm install
npm run dev
& watch the magic happen πHope you liked the boilerplate and if you got any suggestions or comments let me know in the comments down below ! Also welcome any PR's to Etna.