/Backend-Starter-Kit

:truck: A boilerplate for Node.js, Express, Mongoose, Heroku, mLab, Nodemon, PM2, and Babel. REST / GraphQL API Server | PaaS | SaaS | CaaS | CI/CD | Jest | Supertest | Docker | MongoDB | PostgreSQL | Sequelize | Lodash | RxJS | JWT | Passport | Socket.IO | Redis | CircleCI | Apollo

Primary LanguageJavaScriptMIT LicenseMIT

Backend Starter Kit

🚚 A boilerplate for Node.js, Express, Mongoose, Heroku, mLab, Nodemon, PM2, and Babel.

Build Status Coverage Status // Dependency Status devDependency Status

Live Demo

This seed repository provides the following features:

  • ---------- Essentials ----------
  • API routing with Express.
  • Data query language with GraphQL.
  • Object document mapping with Mongoose.
  • Object relational mapping with Sequelize.
  • Utility functions with Lodash.
  • Reactive extensions with ReactiveX.
  • Authenticate requests with Passport.
  • Real-time bidirectional communication with Socket.
  • In-memory data structure store with Redis.
  • Machine learning with TensorFlow.
  • ---------- Tools ----------
  • Next generation JavaScript with Babel.
  • JavaScript static code analyzer with ESLint.
  • Type annotations with Flow.
  • Testing platform with Jest.
  • HTTP testing with Supertest.
  • Test coverage integration with Codecov.
  • Automatically restart application with Nodemon.
  • Keeping application alive with PM2.
  • ---------- Environments ----------
  • Server-side platform with Node.
  • Version control with Git.
  • Code repository with GitHub.
  • Fast and deterministic builds with Yarn.
  • Cloud application hosting with Heroku.
  • Cloud NoSQL database hosting with mLab.
  • Cloud SQL database hosting with ElephantSQL.
  • Cloud Storageβ€Ž hosting with Cloudinary.
  • Cloud memory cache hosting with RedisLabs.
  • Monitoring service with UptimeRobot.
  • Log management service with Papertrail.
  • Performance and security with Cloudflare.
  • Software container with Docker.
  • Continuous integration with CircleCI.

Here are some related seed repositories:

Table of Contents

Getting Started

  1. Clone this Boilerplate
$ git clone --depth 1 https://github.com/Shyam-Chen/Backend-Starter-Kit.git <PROJECT_NAME>
$ cd <PROJECT_NAME>
  1. Install Dependencies
$ yarn install && yarn typed
  1. Run the Application
$ yarn start
  1. Test the Application
$ yarn test
  1. Build the Application
$ yarn build

Dockerization

  1. Build and run the container in the background
$ docker-compose up -d api
  1. Run a command in a running container
$ docker-compose exec api <COMMAND>
  1. Remove the old container before creating the new one
$ docker-compose rm -fs
  1. Restart up the container in the background
$ docker-compose up -d --build api
  1. Push images to Docker Cloud
# .gitignore

  .DS_Store
  node_modules
  npm
  dist
  coverage
+ Dockerfile.dev
+ Dockerfile.prod
  *.log
$ docker login
$ docker build -f Dockerfile.<dev|prod> -t <IMAGE_NAME>:<IMAGE_TAG> .

# checkout
$ docker images

$ docker tag <IMAGE_NAME>:<IMAGE_TAG> <DOCKER_ID_USER>/<IMAGE_NAME>:<IMAGE_TAG>
$ docker push <DOCKER_ID_USER>/<IMAGE_NAME>:<IMAGE_TAG>

# remove
$ docker rmi <REPOSITORY>:<TAG>
# or
$ docker rmi <IMAGE_ID>
  1. Pull images from Docker Cloud
# circle.yml

+ echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
  docker login -u="<DOCKER_USERNAME>" -p="${HEROKU_TOKEN}" registry.heroku.com
- docker build -f Dockerfile.prod -t registry.heroku.com/<HEROKU_PROJECT>/web .
+ docker pull <DOCKER_ID_USER>/<IMAGE_NAME>:<IMAGE_TAG>
  docker push registry.heroku.com/<HEROKU_PROJECT>/web

Configuration

Default environments

Set your local environment variables.

// src/env.js
export const SECRET = process.env.SECRET || <PUT_YOUR_SECRET_HERE>;
export const MONGODB_URI = process.env.MONGODB_URI || <PUT_YOUR_MONGODB_URI_HERE>;
export const POSTGRES_URL = process.env.POSTGRES_URL || <PUT_YOUR_POSTGRES_URL_HERE>;
export const REDIS_PORT = process.env.REDIS_PORT || <PUT_YOUR_REDIS_PORT_HERE>;
export const REDIS_HOST = process.env.REDIS_HOST || <PUT_YOUR_REDIS_HOST_HERE>;
export const SENTRY_DSN = process.env.SENTRY_DSN || <PUT_YOUR_SENTRY_DSN_HERE>;

Deployment environments

Set your deployment environment variables.

# Dockerfile.<dev|prod>
ENV SECRET <PUT_YOUR_SECRET_HERE>
ENV MONGODB_URI <PUT_YOUR_MONGODB_URI>
ENV POSTGRES_URL <PUT_YOUR_POSTGRES_URL_HERE>
ENV REDIS_PORT <PUT_YOUR_REDIS_PORT_HERE>
ENV REDIS_HOST <PUT_YOUR_REDIS_HOST_HERE>
ENV SENTRY_DSN <PUT_YOUR_SENTRY_DSN_HERE>

Using Libraries

  1. Example of REST
import { Router } from 'express';

import { List } from '~/document';

const router = Router();

router.get('/', async (req, res, next) => {
  try {
    const data = await List.find({}).exec();
    res.json(data);
  } catch (err) {
    next(err);
  }
});

export default router;
  1. Example of GraphQL
import gql from 'graphql-tag';

import { List } from '~/document';

export const listTypeDefs = gql`
  type List {
    _id: ID!
    text: String!
  }

  type Query {
    list: [List]
  }
`;

export const listResolvers = {
  Query: {
    async list(root, { text }) {
      try {
        const data = await List.find({}).exec();
        return data;
      } catch (err) {
        console.error(err);
      }
    }
  }
};
  1. Example of Document
import mongoose, { Schema } from 'mongoose';

const listSchema = Schema({
  text: String,
});

export const List = mongoose.model('List', listSchema);
  1. Example of Relational
export default (sequelize, DataTypes) => {
  const List = sequelize.define('List', {
    text: DataTypes.STRING
  });

  return List;
};
  1. Example of Lodash
import { of } from 'rxjs';
import { lowerFirst, pad } from 'lodash';

of(lowerFirst('Hello'), pad('World', 5))
  .subscribe(value => console.log(value));
  // hello
  // World
  1. Example of ReactiveX
import { timer, of } from 'rxjs';
import { mapTo, combineAll } from 'rxjs/operators';

timer(2000)
  .pipe(
    mapTo(of('Hello', 'World')),
    combineAll(),
  )
  .subscribe(value => console.log(value));
  // ["Hello"]
  // ["World"]
  1. Example of Socket
import { io } from '~/core/socket';

io.emit('A', { foo: 'bar' });
io.on('B', data => console.log(data));  // { foo: 'baz' }
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.1/socket.io.js"></script>
<script>
const socket = io();

socket.on('connect', () => console.log('WS: Accept a connection.'));

socket.on('A', data => {
  console.log(data);  // { foo: 'bar' }
  socket.emit('B', { foo: 'baz' });
});
</script>
  1. Example of Redis
import { client } from '~/core/redis';

client.hmset('thing', {
  foo: 'js',
  bar: 'html',
  baz: 'css'
});

client.hgetall('thing', (err, object) => {
  console.log(object);
});

Directory Structure

.
β”œβ”€β”€ src
β”‚   β”œβ”€β”€ core  -> core feature module
β”‚   β”œβ”€β”€ document  -> mongodb models
β”‚   β”œβ”€β”€ graphql  -> query language
β”‚   β”œβ”€β”€ relational  ->  postgresql models
β”‚   β”œβ”€β”€ rest  -> restful api
β”‚   β”œβ”€β”€ shared  -> shared feature module
β”‚   β”œβ”€β”€ api.js
β”‚   └── env.js
β”œβ”€β”€ test  -> e2e testing
β”‚   β”œβ”€β”€ graphql
β”‚   β”‚   └── <api>.spec.js
β”‚   └── rest
β”‚       └── <api>.spec.js
β”œβ”€β”€ .babelrc
β”œβ”€β”€ .editorconfig
β”œβ”€β”€ .eslintrc
β”œβ”€β”€ .flowconfig
β”œβ”€β”€ .gitattributes
β”œβ”€β”€ .gitignore
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ Dockerfile.dev
β”œβ”€β”€ Dockerfile.prod
β”œβ”€β”€ LICENSE
β”œβ”€β”€ README.md
β”œβ”€β”€ circle.yml
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ package.json
β”œβ”€β”€ processes.js
└── yarn.lock