/node-express-starter

A solid starter for an Express API with good error handling

Primary LanguageTypeScriptMIT LicenseMIT

Node Express Starter

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.

Get started

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.

Application structure

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 Errors 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

Tokens

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": "..."
  }
}

Database ORM

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.

Todo

  • 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