Giter VIP home page Giter VIP logo

express-starter's Introduction

Express Starter

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

Build Status Coverage Status

🌈 Live Demo

πŸ’ͺ This seed repository provides the following features:

  • ---------- Essentials ----------
  • Web application framework with Express.
  • Object-document mapping with Mongoose.
  • Make authenticated requests with Passport.
  • File upload with Multer.
  • Real-time communication with WS.
  • ---------- Tools ----------
  • Next generation JavaScript with Babel.
  • JavaScript static code analyzer with ESLint.
  • Code formatter with Prettier.
  • Unit testing with Jest.
  • End-to-End testing with Supertest.
  • Mocking external requests with Nock.
  • Automatically restart application with Nodemon.
  • Keeping application alive with PM2.
  • Reverse proxy with Caddy.
  • ---------- Environments ----------
  • Cloud application hosting with Heroku.
  • Cloud NoSQL database hosting with Atlas.
  • Cloud storage hosting with Cloudinary.
  • Error tracking service with Sentry.
  • Software container with Docker.
  • Continuous integration with CircleCI.
  • Fix and prevent known vulnerabilities with Snyk.
  • Test coverage integration with Codecov.

Note

πŸ€” Think about next-generation application development:

  • Fastify is one of the fastest Node.js web frameworks.
  • Nest uses a modular architecture and allows the choice of either Express or Fastify as the server framework.

If you're interested in Fastify, you can refer to my Fastify Starter.

Table of Contents

Project Setup

Follow steps to execute this boilerplate.

Install dependencies

$ npm install

Start a development server

$ brew services start mongodb-community
$ yarn serve

Produce a production-ready bundle

$ yarn build

Lints and fixes files

$ yarn lint

Runs unit tests

Files: src/**/*.spec.js

$ yarn unit

Runs end-to-end tests

Files: e2e/**/*.spec.js

# Before running the `meas` command, make sure to run the following commands.
$ yarn build
$ yarn preview

# If it's not setup, run it.
$ yarn setup

$ yarn e2e

Measures APIs

Files: e2e/**/*.meas.js

# Before running the `meas` command, make sure to run the following commands.
$ yarn build
$ yarn preview

# If it's not setup, run it.
$ yarn setup

$ yarn meas

Mocks third-party APIs

# If it's not active, run it.
$ yarn active

$ yarn mock

Dockerization

Dockerize an application.

  1. Build and run the container in the background
$ docker-compose up -d mongodb app
  1. Run a command in a running container
$ docker-compose exec app <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 app

Configuration

Control the environment.

Default environments

Set your local environment variables. (use export const <ENV_NAME> = process.env.<ENV_NAME> || <LOCAL_ENV>;)

// src/env.js

export const NODE_ENV = process.env.NODE_ENV || 'development';
export const INDEX_NAME = process.env.INDEX_NAME || 'local';

export const HOST = process.env.HOST || '0.0.0.0';
export const PORT = process.env.PORT || 3000;

export const SECRET_KEY = process.env.SECRET_KEY || 'jbmpHPLoaV8N0nEpuLxlpT95FYakMPiu';

export const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/test';

// ---

export const FACEBOOK_APP_ID = process.env.FACEBOOK_APP_ID || 'XXX';
export const FACEBOOK_APP_SECRET = process.env.FACEBOOK_APP_SECRET || 'XXX';

export const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID || 'XXX';
export const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET || 'XXX';

export const APPLE_SERVICES_ID = process.env.APPLE_SERVICES_ID || 'XXX';
export const APPLE_TEAM_ID = process.env.APPLE_TEAM_ID || 'XXX';
export const APPLE_KEY_ID = process.env.APPLE_KEY_ID || 'XXX';
export const APPLE_PRIVATE_KEY = process.env.APPLE_PRIVATE_KEY || 'XXX';

export const CLOUDINARY_URL = process.env.CLOUDINARY_URL || 'cloudinary://key:secret@domain_name';

export const RATE_LIMIT = process.env.RATE_LIMIT || 0;

export const SENTRY_DSN = process.env.SENTRY_DSN || null;

Continuous integration environments

Add environment variables to the CircleCI build.

# Project Settings > Environment Variables > Add Environment Variable

SECRET_KEY
MONGODB_URI
CLOUDINARY_URL
SENTRY_DSN

File-based environments

If you want to set environment variables from a file.

.
β”œβ”€β”€ e2e
β”œβ”€β”€ envs
β”‚   β”œβ”€β”€ dev.js
β”‚   β”œβ”€β”€ stage.js
β”‚   └── prod.js
β”œβ”€β”€ mock
└── src
// envs/<ENV_NAME>.js

function Environment() {
  this.NODE_ENV = 'production';
  // more...
}

module.exports = new Environment();
$ npm install babel-plugin-transform-inline-environment-variables env-cmd -D
// babel.config.js

    plugins: [
      // ...
      'transform-inline-environment-variables',
    ],
// package.json

  "scripts": {
    // "env-cmd -f ./envs/<ENV_NAME>.js" + "yarn build"
    "build:dev": "env-cmd -f ./envs/dev.js yarn build",
    "build:stage": "env-cmd -f ./envs/stage.js yarn build",
    "build:prod": "env-cmd -f ./envs/prod.js yarn build",
  },

Examples

Directory Structure

The structure follows the LIFT Guidelines.

.
β”œβ”€β”€ e2e
β”œβ”€β”€ mock
β”‚   β”œβ”€β”€ requests
β”‚   └── responses
β”œβ”€β”€ src
β”‚   β”œβ”€β”€ core
β”‚   β”‚   └── ...
β”‚   β”œβ”€β”€ <FEATURE> -> feature modules
β”‚   β”‚   β”œβ”€β”€ __tests__
β”‚   β”‚   β”‚   β”œβ”€β”€ controller.spec.js
β”‚   β”‚   β”‚   β”œβ”€β”€ service.spec.js
β”‚   β”‚   β”‚   └── model.spec.js
β”‚   β”‚   β”œβ”€β”€ controller.js
β”‚   β”‚   β”œβ”€β”€ service.js
β”‚   β”‚   β”œβ”€β”€ model.js
β”‚   β”‚   └── index.js
β”‚   β”œβ”€β”€ <GROUP> -> module group
β”‚   β”‚   └── <FEATURE> -> feature modules
β”‚   β”‚       β”œβ”€β”€ __tests__
β”‚   β”‚       β”‚   β”œβ”€β”€ controller.spec.js
β”‚   β”‚       β”‚   β”œβ”€β”€ service.spec.js
β”‚   β”‚       β”‚   └── model.spec.js
β”‚   β”‚       β”œβ”€β”€ controller.js
β”‚   β”‚       β”œβ”€β”€ service.js
β”‚   β”‚       β”œβ”€β”€ model.js
β”‚   β”‚       └── index.js
β”‚   β”œβ”€β”€ app.js
β”‚   β”œβ”€β”€ env.js
β”‚   └── server.js
β”œβ”€β”€ .editorconfig
β”œβ”€β”€ .eslintrc
β”œβ”€β”€ .gitignore
β”œβ”€β”€ .prettierrc
β”œβ”€β”€ babel.config
β”œβ”€β”€ Caddyfile
β”œβ”€β”€ circle.yml
β”œβ”€β”€ develop.Dockerfile
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ jest.config.js
β”œβ”€β”€ LICENSE
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ package.json
β”œβ”€β”€ processes.js
β”œβ”€β”€ produce.Dockerfile
└── README.md

Microservices

Microservice architecture – a variant of the service-oriented architecture structural style – arranges an application as a collection of loosely coupled services. In a microservices architecture, services are fine-grained and the protocols are lightweight.

See Server-side Micro-Fullstack for instructions on how to create microservices from source code.

express-starter's People

Contributors

dependabot[bot] avatar shyam-chen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

express-starter's Issues

Rest error text-list.spec.js

Hello, first of all thank you for posting this boilerplate πŸ‘

Every installation of the boilerplate occurred successfully however when starting the project with the sudo yarn start. I'm getting several errors of the test/rest/text-list.spec.js and /__/list/relational, I was checking the commits sent by you and I realized that a large part of his CircleCI Builds occurring normally and without error.

Could you explain why I'm having these mistakes?

My changelog of build send to CircleCI.

#!/bin/bash -eo pipefail
docker-compose exec api yarn unit
yarn run v1.3.2
$ jest --coverage --forceExit
Determining test suites to run...

 RUNS  ...

sequelize deprecated String based operators are now deprecated. Please use Symbol based operators for better security, read more at http://docs.sequelizejs.com/manual/tutorial/querying.html#operators node_modules/sequelize/lib/sequelize.js:236:13

 RUNS  ...


 RUNS  ...

(node:68) DeprecationWarning: Mongoose: mpromise (mongoose's default promise library) is deprecated, plug in your own promise library instead: http://mongoosejs.com/docs/promises.html

 RUNS  ...


 RUNS  ...

GET /__/list 200 - - 612.198 ms
GET /__/list/count 200 2 - 48.484 ms
GET /__/list?_id=59901c7dbc9187001ec32c7b 200 2 - 24.497 ms

 RUNS  ...

GET /__/list?text=v 200 2 - 15.068 ms
GET /__/list/pagination/2/5 200 378 - 69.153 ms

 RUNS  ...

POST /__/list 200 24 - 34.436 ms
PUT /__/list/59901c7dbc9187001ec32c7b 200 26 - 34.519 ms
DELETE /__/list/59901c7dbc9187001ec32c7b 200 26 - 15.032 ms

 RUNS  ...

 FAIL  test/rest/text-list.spec.js

 RUNS  ...

  ● Console

    console.log src/api.js:70
       [*] App: Bootstrap Succeeded.
    console.log src/api.js:71
       [*] Host: http://localhost:3000/.
    console.log src/api.js:107
       [*] Redis: Connection Succeeded.
    console.log src/api.js:86
       [*] Postgres: Connection Succeeded.
    console.log src/api.js:78
       [*] Mongo: Connection Succeeded.
    console.log node_modules/sequelize/lib/sequelize.js:1062
      Executing (default): INSERT INTO "Lists" ("id","text","createdAt","updatedAt") VALUES (DEFAULT,'Web GO','2017-11-26 15:16:26.822 +00:00','2017-11-26 15:16:26.822 +00:00') RETURNING *;
    console.log node_modules/sequelize/lib/sequelize.js:1062
      Executing (default): SELECT "id", "text", "createdAt", "updatedAt" FROM "Lists" AS "List";


 RUNS  ...

  ● REST β€Ί should POST /__/list/relational

    expect(received).toBe(expected)
    
    Expected value to be (using ===):
      200
    Received:
      500
      
      at Object.it (test/rest/text-list.spec.js:78:24)
          at <anonymous>
      at process._tickDomainCallback (internal/process/next_tick.js:228:7)

  ● REST β€Ί should GET /__/list/relational

    expect(received).toBe(expected)
    
    Expected value to be (using ===):
      200
    Received:
      500
      
      at Object.it (test/rest/text-list.spec.js:86:24)
          at <anonymous>
      at process._tickDomainCallback (internal/process/next_tick.js:228:7)


 RUNS  ...


 RUNS  ...


 RUNS  ...

POST /__/list/relational 500 - - 152.110 ms
GET /__/list/relational 500 - - 17.545 ms

 RUNS  ...

 PASS  test/graphql/text-list.spec.js

 RUNS  ...


Test Suites: 1 failed, 1 passed, 2 total
Tests:       2 failed, 9 passed, 11 total
Snapshots:   0 total
Time:        3.95s
Ran all test suites.
-------------------|----------|----------|----------|----------|----------------|
File               |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
-------------------|----------|----------|----------|----------|----------------|
All files          |     55.6 |    35.94 |    41.67 |       60 |                |
 src               |       76 |    59.09 |    44.44 |    85.71 |                |
  api.js           |    72.09 |       50 |    44.44 |    82.86 |... 63,87,98,99 |
  config.js        |      100 |    64.29 |      100 |      100 |      3,5,6,8,9 |
 src/document      |    43.33 |        0 |        0 |       50 |                |
  authorization.js |    39.29 |        0 |        0 |    45.83 |... 44,45,51,52 |
  index.js         |      100 |      100 |      100 |      100 |                |
  text-list.js     |      100 |      100 |      100 |      100 |                |
 src/graphql       |    18.75 |        0 |      100 |       20 |                |
  authorization.js |    66.67 |      100 |      100 |    66.67 |             18 |
  index.js         |      100 |      100 |      100 |      100 |                |
  text-list.js     |     7.41 |        0 |      100 |        8 |... 88,89,90,92 |
 src/relational    |    93.33 |       75 |      100 |    93.33 |                |
  authorization.js |      100 |      100 |      100 |      100 |                |
  index.js         |    90.91 |       75 |      100 |    90.91 |             19 |
  text-list.js     |      100 |      100 |      100 |      100 |                |
 src/rest          |    55.26 |    26.92 |    37.93 |    58.82 |                |
  authorization.js |    19.05 |        0 |        0 |    23.53 |... 57,62,63,64 |
  email.js         |    22.22 |        0 |        0 |       25 |... 17,19,20,21 |
  index.js         |      100 |      100 |      100 |      100 |                |
  text-list.js     |    83.05 |     87.5 |    91.67 |    82.14 |... 151,153,165 |
-------------------|----------|----------|----------|----------|----------------|
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Exited with code 1

Thanks ❀️

VS Code Launch

Is anyone using VS Code and have a functioning launch-script? I'm trying to figure out how to use nodemon+babel-node but with no success. Maybe it can be part of the boilerplate project?

GraphQL authenticate middleware

I'm new to GraphQL and didn't really understand how the application is supposed to authenticate the user.

What I can see is this authentication strategy:

passport.use(new JWTStrategy(
  {
    jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
    secretOrKey: SECRET,
  },
  async (jwtPayload, done) => {
    try {
      if (Date.now() > jwtPayload.expires) return done('Token expired');

      const user = await User.findOne({ username: jwtPayload.username }).exec();
      return done(null, user);
    } catch (error) {
      return done(error);
    }
  },
));

But in the GraphQL context we are assuming the authentication is done at earlier middleware?

const context = async ({ req }) => {
  // if (!req.user) throw new Error('You must be logged in to query this schema');

  return {
    user: req.user,
  };
};

I set the header in the GraphQL playground but the req.user was still undefined:

{
  "authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODBjYTc0MjljYWQwMzRhODVmODFjMiIsImVtYWlsIjoiamlhQHFpdS5pbyIsImlhdCI6MTU4NTQ5ODc0MCwiZXhwIjoxNjE3MDU2MzQwfQ.OUQn8FJif6t2y8u8UX-7qsSGrjvlPxmCUs_a2fZBNOM"
}

In my earlier Express-application, I could specify which endpoints I wanted to run the Authentication, can we do something similar here?

Demo not working.

Hi, I think this might be the PERFECT boilerplate for my SaaS startup. I however can't load the demo version to try it out :(

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.