This is a simple but complete boilerplate for a NodeJS REST API app using ExpressJS, validation with Joi, caching with Redis, and backed by a PostgreSQL database.
You will need to have Docker and NodeJS installed. Run docker-compose up -d
. This will start Postgres, Redis and the Node app.
You will need to run the script to create the database and required tables. Run yarn createdb
.
Then open up your favourite endpoint testing tool like Postman or Insomnia, and start hitting http://localhost:3000.
There is clear separation between app layers to make code navigation a breeze.
Router -> Controller -> Service -> Persistence.
Routers define middleware and final functions in the pipeline.
Controllers orchestrate the rest of the call-graph. They can call into multiple services and components. They do not throw errors, but rather pass custom Error
s to a controller-level error handler. They are the only point beyond routers that send responses to clients.
Services do the domain-specific work, perform any data transformations, and can call the persistence layer as well as trigger any events.
Persistence is solely to save to a data store. It will have to do any required sanitization of input as well.
Client --> Router --> Controller --> ServiceA --> PersistenceA
\
\ --> ServiceB --> PersistenceB
The app has 2 types of tokens. Access Tokens and Refresh Tokens.
Access tokens are required on every request (except when signing in/up) as a header "Authorization": "Bearer ..."
.
The Access Token has an expiry. When it expires, the client is expected to use the Refresh Token to generate a new Access Token for subsequent requests.
Upon signup, signin or refresh, the client will receive both an access and a refresh tokens:
{
"tokens": {
"access_token": "...",
"refresh_token": "..."
}
}
This app uses pg
drivers rather than a standard ORM. This means, yes, you have to write your own SQL, but if you don't know SQL, maybe you should't be interacting with an SQL database :)
You might be asking, "why not Prisma? It's the new hotness!". Well, it certainly does have a lot of stars on GitHub, but it also has a lot of issues on GitHub too. At the time of writing this, it's around 2.6k, which is a lot. There's also Sequelize which I have used heavily in the past, but I'm not a fan of creating Sequelize-specific models to manage the shape of data. It's quite heavily tied to the ORM, rather than the actual data.
So I decided to go with something more "stable" and barebones. Old and boring may not be cool, but it works predictably most of the time.
- Improve error handling
- Add JWT auth refresh. Needs error response of "expired"
- Add route to refresh tokens
- Add password encryption and decryption
- Add Postgres into docker-compose
- Add persistence layer for User
- Add persistence layer for UserTokens
- Add Redis into docker-compose
- Finish SQL for all routes
- Add caching functions for UserTokens
- Revisit logger use
- Add NodeJS events to do handle analytics tracking
- Add scheduled cleanup worker for orphaned database tokens
- Add scheduled cleanup worker for orphaned cache tokens
- Add the ability to run migrations
- Add all the test
- Add Insomnia requests to repo
- Add Swagger docs