Skip to content

TheBumpaster/boilerplate_rest_api_nodejs

Repository files navigation

NodeJS REST API Boilerplate


Description

The goal of this assignment is to build a REST API in NodeJS that is easy scalable and deployable with Docker with minimum API functionality implemented.

Table of contents

Technical Prerequisites

  • NodeJS v16

  • TypeScript v4.4

  • MongoDB v4.2

  • Docker v20.10

  • Docker Compose v1.29

  • Google Cloud SDK (optional)

    • Google Cloud SDK v356.0.0
    • alpha v2021.09.03
    • beta v2021.09.03
    • bq v2.0.71
    • core v2021.09.03
    • gsutil v4.67

Getting started

# install dependencies
npm install

# serve typescript
npm run serve

# build source files
npm run build

# start server from dist
npm run start

# run tests
npm run test

# run lint check
npm run lint

# generate technical documentation
npm run docs

# serve documentation on web http://localhost:5000
npm run serve:docs

img_1.png

Development

You might want to create a new network on docker or update docker-compose service network property.

docker network create network_name

To start a development server stack, build compose images.

# build docker image with docker-compose
docker-compose -f docker-compose-yml up -d

# re-build (in case of environment keys updates)
docker-compose up docker-compose.yml --build -d

Note: Running docker-compose is for development as it will run serve script from package.json.

Production / Testing / Docker deployment

# Build the image
docker build --rm -f Dockerfile -t povio_assignment_server:latest .

# Push image to docker hub
docker push --quiet povio_assignment_server:latest

Navigate to http://localhost:{yourport}/api/docs for Swagger API Explorer.

img.png

Setting up environment

These are required environment keys, they do not have default values.

PORT=yourServicePortNumber

DB_HOST=yourDatabaseHost
DB_PORT=yourDatabasePort
DB_NAME=yourDatabaseName

JWT_SECRET=yourJWTSecretKey
JWT_ISSUER=yourJWTIssuer
JWT_AUDIENCE=yourJWTAudience
JWT_EXPIRY=yourJWTExpiryTime(eg10m)

SECURITY_KEY=yourSecurityKey
SECURITY_VECTOR=yourSecurityKeyVector

JWT_SECRET is important to identify valid user tokens. SECURITY_KEY is important to be able to compare user password on submission SECURITY_VECTOR is important to be able to decipher SECURITY_KEY

Database requires only 3 variables, but can also support few more in case you need them to connect your DB instance to a cluster.

DB_USER=yourDatabaseUser
DB_PASS=yourDatabasePassword
DB_AUTH_SOURCE=yourMongoDBAuthorizationSourceCallback

NODE_ENV is being defined by the Docker image or by the Test Suite Environment

To enable testing environment create a new file in root directory .env.test with the following content:

NODE_ENV=test
PORT=9999

JWT_SECRET=CatsAndDogs
JWT_ISSUER=localhost
JWT_AUDIENCE=localhost:9999
JWT_EXPIRY=10m

SECURITY_KEY=DogsAndCats
SECURITY_VECTOR=CatsAndDogs

Database keys are not required as they will be autogenerated on initialization of MongoDB MemoryServer. NODE_ENV=test is required.

img_2.png

Project Structure

Project structure has been taken from MVC principles, but due to event based services I have adjusted it for easier scaling or even splitting into microservices.

['povio_assignment']$:
|-> dist (Generated JavaScript Files)
|-> docs (Generated Technical Documentation)
|-> node_modules (Library Root)
|-> server (TypeScript Source Files)
|   |-> api (API Module)
|   |   |-> middleware (API Middlewares)
|   |   |   |-> authorization.ts (JWT Authentication Middleware)
|   |   |-> util (API Utilities)
|   |   |   |-> response.ts (Response Builder)
|   |   |   |-> security.ts (Password hashing)
|   |   |-> v1 (API V1 Route Stack)
|   |   |   |-> health (Probe API Routes)
|   |   |   |   |-> index.ts (Route Stack)
|   |   |   |-> system (System API Routes)
|   |   |   |   |-> index.ts (Router Stack)
|   |   |   |   |-> validators.ts (Helpers)
|   |   |   |-> users (Users API Routes)
|   |   |   |   |-> index.ts (Router Stack)
|   |   |   |   |-> validators.ts (Helpers)
|   |   |   |-> api.spec.yaml (OpenAPI V3 Specification)
|   |   |-> router.ts (Express Router)
|   |-> config
|   |   |-> application.ts (Custom environment config)
|   |   |-> constants.ts (Server global constants)
|   |-> models
|   |   |-> users (User Model Module)
|   |   |   |-> index.ts (Main Model Export)
|   |   |   |-> schema.ts (User Schema Interface Definition)
|   |   |   |-> service.ts (User Schema Statics Methods)
|   |-> services
|   |   |   |-> database
|   |   |   |   |-> index.ts (Database client connection methods)
|   |   |   |-> logger
|   |   |   |   |-> index.ts (Logger class to utilize winston logger transports and levels)
|   |-> index.ts (Main Express API Server)
|-> tests (TypeScript Source Test Files)
|-> .dockerignore (Ignore files)
|-> .env (Environment configuration)
|-> .env.test (Test environment configuration)
|-> .eslintrc.js (Code Styling Rules)
|-> .gitignore Ignore files)
|-> docker-compose.yml (Local Docker Development Stack)
|-> Dockerfile (Docker Image)
|-> package.json (NPM package handling)
|-> readme.md (This File)
|-> tsconfig.json (TypeScript Configuration)
|-> typedocs.json (TypeDocs Configuration)

List of packages

  • compression @ Node.js compression middleware.
  • cors @ CORS is a node.js package for providing a connect middleware that can be used to enable CORS with various options.
  • express @ Fast, unopinionated, minimalist web framework for node.
  • helmet @ Helmet helps you secure your Express apps by setting various HTTP headers.
  • joi @ The most powerful schema description language and data validator for JavaScript.
  • jsonwebtoken @ An implementation of JSON Web Tokens
  • mongoose @ Mongoose is a MongoDB object modeling tool designed to work in an asynchronous environment.
  • swagger-ui-express @ This module allows you to serve auto-generated swagger-ui generated API docs from express.
  • winston @ A logger for just about everything.
  • yaml @ JavaScript parser and stringifier for YAML, a human friendly data serialization standard.

Deploying the solution to Google Cloud Console

I believe Serverless Containers are the future of deploying Containerized applications. The assignment web service runs on Google Cloud Run. I also highly recommend this approach.

  1. Download and install Node.js
  2. Select or create a Google Cloud Platform Console project
  3. Enable billing for your project (there's a $300 free trial)
  4. Select or create Atlas Cluster project
  5. Enable billing for your project (there's a free tier) to copy connection string
  6. Do some devops:
# Ensure that you have a Live MongoDB URL inside your variable .env

# MongoDB Atlas URI looks like this mongodb://<username>:<password>@<hostname>/<database name>

# DB_USER=<username>
# DB_PASS=<password>
# DB_HOST=<hostname>
# DB_PORT=
# DB_NAME=<database name>

# Build a Docker image
docker build --rm -f "Dockerfile" -t boilerplate_rest_api_nodejs:latest .

# Tag the image to a Google Cloud Container Registry URL
docker tag boilerplate_rest_api_nodejs us.gcr.io/[PROJECT ID]/boilerplate_rest_api_nodejs

# Push the newly tagged image to the Google Cloud Container Registry.
docker push us.gcr.io/[PROJECT_ID]/boilerplate_rest_api_nodejs

Google Container Registry provides secure, private Docker image storage on Google Cloud Platform. Our API follows the Docker Registry API specification, so we are fully compatible with the Docker CLI client, as well as standard tooling using the Docker Registry API.

  1. Sign in your Google Cloud Console
  2. Select Container Registry
  3. You will see the latest version of the pushed image.
  4. Select Deploy to Cloud Run
  5. You will be redirected to the Google Cloud Run page.
  6. Fill in the required fields.
  7. Click on CREATE button below your fields.
  8. Congratulations! Your app now runs on Serverless !!!