/production-ready-expressjs-server

Express.js server that implements production-ready error handling and logging following latest best practices.

Primary LanguageJavaScriptMIT LicenseMIT

Build Status Known Vulnerabilities codecov.io License

This is an Express.js based Nodejs server that implements production-ready error handling and logging following latest best practices.

This project is inspired by an idea to quickly create a production ready project with all the required infrastructure at low cost yet with important security measures in place and ability to quickly scale in order to ship a quality product to early adopters. Ideal for quickly starting an app to validate ideas and scale if needed.

One of the main points is that we do not need to deal with setting up servers or databases to validate an idea. Therefore, this opensource project relies on cloud solutions for managing DBs, deployments, sending transactional emails, which have free plans with useful and secure features. And you can always switch to a paid plan if your projects grow fast and you need more power.

Current stack is JavaScript/Nodejs, MongoDB, Redis, Graphql. Now for deployment.

Features

This project uses Git hook to validate commit messages based on community standards

I am always open to your feedback

ToDo (with React, Vue and Angular):

  • Authentication (Gmail, Facebook, LinkedIn, Twitter)
  • Password recovery
  • add/remove social accounts
  • Backend (RBAC, user management)
  • Logic to separate free/paid services
  • Basic CSS with something simple like tailwindcss
  • GDPR ready (cookies, settings)
  • TypeScript (maybe)
  • Scaffolding tool to choose from the mentioned FWs/Libs, etc.

Get started

Security in production

Additional settings

Set up environment variables

Rename *.sample.js files in /server/config directory:

  • default.sample.js -> default.js
  • production.sample.js -> production.js
  • test.sample.js -> test.js

Create .env file in the root of the project with the following lines:

//.env

MONGO_DB=mongodb+srv://<user>:<password>@cluster0-clxgl.mongodb.net/test?retryWrites=true&w=majority
PRISMA_URL=http://localhost:4466
NGINX_PORT=3045 // or whatever you want

More details on how config works see node-config. You may also find Securing production config files useful

Install and start Docker

  • Install Docker (if not yet installed) and make sure it runs
  • Run docker-compose up

Install npm dependencies

  • Run npm install

Create account and connect to MongoDB Atlas cloud instance using the FREE plan

  • Create an account with MongoDB Atlas using the FREE plan and follow instructions here

Set up Prisma

  1. Prisma serves as an ORM. Run npm i -g prisma to install it
  2. Schema is defined here ./prisma/datamodel.prisma
  3. Run prisma deploy or (npm run deploy)
  • Later, during development, use npm run get-schema to download schema from endpoint to ./src/generated/prisma.graphql. Note that it will run automatically on prisma deploy or (npm run deploy) as it is set up in post-deploy hook in /prisma/prisma.yml
  • Prisma GraphQl playground is available here http://localhost:4466
  • Apollo server GraphQl playground - http://localhost:${NGINX_PORT}/graphql

Create account and connect to RedisLabs cloud instance using the FREE plan

  • Create an account with Redislabs using the FREE plan (choose Cloud Hosted - free up to 30MB) and follow instructions here

!!!Note!!! the redis url looks as follows (the part after @ is the Endpoint from the dashboard configuration tab):

redis://:<password>@redis-<...>.cloud.redislabs.com:<port>

Create account and setup Sentry error tracking

  • Create a Sentry account here
  • Add your-sentry-dsn to all configuration files in /config dir
  sentry: {
    dsn: 'your-sentry-dsn',
  },

Create account and setup MailJet to send transactional emails

  • Create a MailJet account here
  • Add your-mailjet-api-key and your-mailjet-secret to all configuration files in /config dir
  mailjet: {
    api_key: 'your-mailjet-api-key',
    secret: 'your-mailjet-secret',
  },
  • Important!!! You need to use a domain-based email address as an email sender (e.g. your project's domain name) to ensure emails are delivered to the inbox. Otherwise, they will end up in spam (including example@gmail.com once). In your MailJet account you can verify your email and take additional measures (e.g.SPF and DKIM settings) to ensure your emails are delivered.

Kue UI dashboard

  • The dashboard is available under http://localhost:3050/active or via nginx http://localhost:${NGINX_PORT}/kue/active

Run server

  • npm run dev - development mode or
  • npm run start - production mode
  • docker-compose -f docker-compose.yml -f test-env.yml up - run server in test environment

Testing and linting

  • npm run test:unit - run unit tests
  • npm run test:int - run integration tests
  • npm run coverage - test coverage
  • npm run lint - lint

Making changes to Graphql schemas

  • update/add data model /prisma/datamodel.prisma
  • update/add schema /src/graphql/schema.graphql
  • update/add queries, mutations or subscriptions /src/graphql/resolvers/
  • run npm run deploy to update prisma data model and generate schema in /generated

Test error handling

  • navigate to /api/crash/ and click on any of the listed options

    Note, that crash routes for testing error handling are not available in production env

Error handling implementation explained

Closing prisma to the outside world

  • Add your secret in prisma/prisma.yml
secret: putYourSuperSecretTextHere

  • Add the same secret in src/db/prisma.js
secret: 'putYourSuperSecretTextHere',

  • run npm run deploy

Now the http://localhost:${NGINX_PORT}/graphql endpoint will work as expected.

However the http://localhost:4466 will return "Your token is invalid" error. To be able to use it, you need to generate an authorization token and use it in HTTP headers. Here is how you do it:

  • run npm run get-prisma-token
  • copy the generated token
  • insert the following HTTP headers (bottom left corner) in graphql playground under http://localhost:4466
{
  "Authorization":"Bearer 'generated token'" // mind the space between "Bearer" and the token
}

Pushing images to docker hub

To push images to Docker Hub you need to provide your Docker user name and password as environment variables. Refer to Travis documentation for more details

Once environment variables set, uncomment related lines in .travis.yml file