Express REST API with JWT Authentication and support for sqlite, mysql, and postgresql
development
, testing
, and production
npm i
and npm start
Start by cloning this repository
# HTTPS
$ git clone https://github.com/aichbauer/express-rest-api-boilerplate.git
then
# cd into project root
$ yarn
# to use mysql
$ yarn add mysql2
# to use postgresql
$ yarn add pg pg-hstore
# start the api
$ yarn start
or
# cd into project root
$ npm i
# to use mysql
$ npm i mysql2 -S
# to use postgresql
$ npm i -S pg pg-hstore
# start the api
$ npm start
sqlite is supported out of the box as it is the default.
This boilerplate has 4 main directories:
Controllers in this boilerplate have a naming convention: ModelnameController.js
and uses an object factory pattern.To use a model inside of your controller you have to require it.We use Sequelize as ORM, if you want further information read the Docs.
Example Controller for all CRUD oparations:
const Model = require('../models/Model');
const ModelController = () => {
const create = async (req, res) => {
// body is part of a form-data
const { value } = req.body;
try {
const model = await Model.create({
key: value
});
if(!model) {
return res.status(400).json({ msg: 'Bad Request: Model not found' });
}
return res.status(200).json({ model });
} catch (err) {
// better save it to log file
console.error(err);
return res.status(500).json({ msg: 'Internal server error' });
}
};
const getAll = async (req, res) => {
try {
const model = await Model.findAll();
if(!models){
return res.status(400).json({ msg: 'Bad Request: Models not found' });
}
return res.status(200).json({ models });
} catch (err) {
// better save it to log file
console.error(err);
return res.status(500).json({ msg: 'Internal server error' });
}
};
const get = async (req, res) => {
// params is part of an url
const { id } = req.params;
try {
const model = await Model.findOne({
where: {
id,
},
});
if(!model) {
return res.status(400).json({ msg: 'Bad Request: Model not found' });
}
return res.status(200).json({ model });
} catch (err) {
// better save it to log file
console.error(err);
return res.status(500).json({ msg: 'Internal server error' });
}
};
const update = async (req, res) => {
// params is part of an url
const { id } = req.params;
// body is part of form-data
const { value } = req.body;
try {
const model = await Model.findById(id);
if(!model) {
return res.status(400).json({ msg: 'Bad Request: Model not found' });
}
const updatedModel = await model.update({
key: value,
)};
return res.status(200).json({ updatedModel });
} catch (err) {
// better save it to log file
console.error(err);
return res.status(500).json({ msg: 'Internal server error' });
}
};
const destroy = async (req, res) => {
// params is part of an url
const { id } = req.params;
try {
const model = Model.findById(id);
if(!model) {
return res.status(400).json({ msg: 'Bad Request: Model not found' })
}
await model.destroy();
return res.status(200).json({ msg: 'Successfully destroyed model' });
} catch (err) {
// better save it to log file
console.error(err);
return res.status(500).json({ msg: 'Internal server error' });
}
};
// IMPORTANT
// don't forget to return the functions
return {
create,
getAll,
get,
update,
destroy,
};
};
model.exports = ModelController;
Models in this boilerplate have a naming convention: Model.js
and uses Sequelize to define our Models, if you want further information read the Docs.
Example User Model:
const Sequelize = require('sequelize');
// for encrypting our passwords
const bcryptSevice = require('../services/bcrypt.service');
// the DB connection
const sequelize = require('../../config/database');
// hooks are functions that can run before or after a specific event
const hooks = {
beforeCreate(user) {
user.password = bcryptSevice.password(user);
},
};
// naming the table in DB
const tableName = 'users';
// the actual model
const User = sequelize.define('User', {
username: {
type: Sequelize.STRING,
unique: true,
},
password: {
type: Sequelize.STRING,
},
}, { hooks, tableName });
// instead of using instanceMethod
// in sequelize > 4 we are writing the function
// to the prototype object of our model.
// as we do not want to share sensitive data, the password
// field gets ommited before sending
User.prototype.toJSON = function () {
const values = Object.assign({}, this.get());
delete values.password;
return values;
};
// IMPORTANT
// don't forget to export the Model
module.exports = User;
Policies are middleware functions that can run before hitting a apecific or more specified route(s).
Example policy:
Only allow if the user is marked as admin.
Note: this is not a secure example, only for presentation puposes
module.exports = (req, res, next) => {
if(req.body.userrole === 'admin') {
// do some verification stuff
const verified = verifyAdmin(req.body.userid);
if(verified) {
return next();
}
return res.status(401).json({ msg: 'Unauthorized' });
}
return res.status(401).json({ msg: 'Unauthorized' });
};
To use this policy on all routes that only admins are allowed:
api.js
const adminPolicy = require('./policies/admin.policy');
app.all('/admin/*', (req, res, next) => adminPolicy(req,res,next));
Or for one specific route
api.js
const adminPolicy = require('./policies/admin.policy');
app.get('/admin/myroute',
(req, res, next) => adminPolicy(req,res,next),
(req, res) => {
//do some fancy stuff
});
The auth.policy
checks wether a JSON Web Token
(further information) is send in the header of an request as Authorization: Bearer [JSON Web Token]
or inside of the body of an request as token: [JSON Web Token]
.The policy runs default on all api routes that are are prefixed with /private
. To map multiple routes read the docs from express-routes-mapper
.
To use this policy on all routes of a specific prefix:
app.js
app.use('/prefix', yourRoutes);
app.all('/prefix', (req, res, next) => auth(req, res, next));
or to use this policy on one specific route:
app.js
app.get('/specificRoute',
(req, res, next) => auth(req, res, next),
(req, res) => {
// do some fancy stuff
});
Services are little useful snippets, or calls to another API that are not the main focus of your API.
Example service:
Get comments from another API:
const commentService = () => {
const getComments = async () => {
try {
const res = await fetch('https://jsonplaceholder.typicode.com/comments', {
method: 'get'
});
// do some fancy stuff with the response
} catch (err) {
// handle a error
}
};
return {
getComments,
};
};
module.exports = commentService;
Holds all the server configurations.
Note: if you use msql make sure mysql server is running on the machine
Note: if you use postgres make sure postgres server is running on the machine
This two files are the way to establish a connaction to a database.
You only need to touch connection.js, default for development
is sqlite, but it is easy as typing mysql
or postgres
to switch to another db.
Note: to run a mysql db install these package with:
yarn add mysql2
ornpm i mysql2 -S
Note: to run a postgres db run these package with:
yarn add pg pg-hstore
ornpm i -S pg pg-hstore
Now simple configure the keys with your credentials.
{
database: 'databasename',
username: 'username',
password: 'password',
host: 'localhost',
dialect: 'sqlite' || 'mysql' || 'postgres',
}
To not configure the production code.
To start the DB, add the credentials for production. add environment variables
by typing e.g. export DB_USER=yourusername
before starting the api.
Here you define all your routes for your api. It doesn't matter how you structure them. By default they are mapped on privateRoutes
and publicRoutes
. You can define as much routes files as you want e.g. for every model or for specific use cases, e.g. normal user and admins.
For further information read the docs of express-routes-mapper.
Example for User Model:
Note: Only supported Methods are POST, GET, PUT, and DELETE.
userRoutes.js
const userRoutes = {
'POST /user': 'UserController.create',
'GET /users': 'UserController.getAll',
'GET /user/:id': 'UserController.get',
'PUT /user/:id': 'UserController.update',
'DELETE /user/': 'UserController.destroy',
};
module.exports = userRoutes;
To use these routes in your application, require them in the config/index.js and export them.
const userRoutes = require('./userRoutes');
const config = {
allTheOtherStuff,
userRoutes,
};
module.exports = config;
api.js
const mappedUserRoutes = mapRoutes(config.userRoutes, 'api/controllers/');
app.use('/prefix', mappedUserRoutes);
// to protect them with authentication
app.all('/prefix/*', (req, res, next) => auth(req, res, next));
All test for this boilerplate uses Jest and supertest for integration testing. So read their docs on further information.
The setup directory holds the _setup.js
which holds beforeAction
which starts a test express application and connects to your test database, and a afterAction
which closes the db connection.
Note: those request are asynchronous, we use
async await
syntax.
Note: As we don't use import statements inside the api we also use the require syntax for tests
To test a Controller we create fake requests
to our api routes.
Example GET /user
from last example with prefix prefix
:
const request = require('supertest');
const {
beforeAction,
afterAction,
} = require('../setup/_setup');
let api;
beforeAll(async () => {
api = await beforeAction();
});
afterAll(() => {
afterAction();
});
test('test', async () => {
const token = 'this-should-be-a-valid-token';
const res = await request(api)
.get('/prefix/user')
.set('Accept', /json/)
// if auth is needed
.set('Authorization', `Bearer ${token}`)
.set('Content-Type', 'application/json')
.expect(200);
// read the docs of jest for further information
expect(res.body.user).toBe('something');
});
Are usually automatically tested in the integration tests as the Controller uses the Models, but you can test them separatly.
There are no automation tool or task runner like grunt or gulp used for this boilerplate. These boilerplate only uses npm scripts for automatization.
This is the entry for a developer. This command:
By default it uses a sqlite databse, if you want to migrate the sqlite db by each start, disable the prestart
and poststart
command. Also mind if you are using a sqlite database to delete the drop-sqlite-db
in the prepush hook.
.api/api.js
NODE_ENV
to development
development
This command:
npm run lint
(eslint) with the airbnb styleguide without arrow-parens rule for better readabilityNODE_ENV
to testing
database.sqlite
for the testjest --coverage
for testing with Jest and the coveragedatabase.sqlite
after the testThis command:
production
production
Before running on production you have to set the environment vaiables:
Optional:
npm run dev
- simply start the server withou a watchernpm run create-sqlite-db
- creates the sqlite databasenpm run drop-sqlite-db
- drops ONLY the sqlite databasenpm run lint
- linting with eslintnpm run nodemon
- same as `npm start``npm run prepush
- a hook wich runs before pushing to a repository, runs npm test
and npm run dropDB
pretest
- runs linting before npm test
test-ci
- only runs tests, nothing in pretest, nothing in posttest, for better use with ci toolsMIT © Lukas Aichbauer
Express实现路由分发控制、RESTful API 标签(空格分隔): Node.js 最近在用Express作为自己的WEB应用框架,其中最为迷惑的就是Express的路由控制和分发,在网上搜了很多资料,但是大部分的资料都是将Express的路由控制写在了app.js入口文件中,但是这样的写法写一些Demo是可以的,但是在实战项目中基本上不会这样来写,因为随着项目的庞大,在app.js入口文
因为这个是为了我自己的博客搭建的,所以里面有个最重要的内容。 文章的增删查改。 文件的增删查改一般会用到数据库的几个最基本的功能。 新增:insert 删除:delete 查询:select 修改:update 1.新增文章 已知,文章的主要结构是“标题,内容,时间”,加上次要内容“分类,标签”,新增文章的sql语句可以这样写 createArticle:insert into article(
后端渲染页面有以下步骤: (以渲染一个http:localhost:8000/login 页面为例) 进入app.js 首先引入路由配置文件, var loginRouter = require( './routes/login' ) //再创建路由级中间件 app.use('/', loginRouter) 在routes中创建login.js文件 ,里面写的是数据 //
app.engine(ext, callback) 注册模板引擎的 callback 用来处理ext扩展名的文件 默认情况下, 根据文件扩展名require() 对应的模板引擎。 比如你想渲染一个 "foo.jade" 文件,Express会在内部执行下面的代码,然后会缓存require(),这样就可以提高后面操作的性能 把模板ejs文件后缀修改为html var express = requir
RESTful API 概述 一套关于设计请求的规范 GET 获取数据 http://localhost:3000/user 获取用户列表 POST 添加数据 http://localhost:3000/user 添加用户数据 PUT 更新数据 http://localhost:3000/user/1 更新id=1的用户数据 DELETE 删除数据
express() 创建一个express应用程序 var express = require('express'); var app = express(); app.get('/', function(req, res){ res.send('hello world'); }); app.listen(3000); Application app.set(name, value) 将设置项
目录 1、索引操作 创建索引库 查看索引库的信息 2、文档(document)操作 2.1、添加操作 2.1.1、添加文档 2.1.2、不指定id自动生成id 2.1.3、批量添加,注意:json不要换行 2.2、修改操作 2.2.1、根据id直接覆盖修改 2.2.2、指定修改某个field 2.2.3、批量修改 2.3、删除操作 2.3.1、删除文档 2.3.2、批量删除 3、查询操作 1、索引
1.body-parser是什么? body-parser是一个HTTP请求体解析中间件,使用这个模块可以解析JSON、Raw、文本、URL-encoded格式的请求体,Express框架中就是使用这个模块做为请求体解析中间件。 body-parser模块是一个Express中间件,它使用非常简单且功能强大 2.下载配置body-parser npm install body-parser 3.
API RESTful em Express, Mongoose, Mocha e Chai. Scripts Os seguintes scripts estão disponiveis com yarn run SCRIPT ou npm run SCRIPT Script Descrição test Roda o linter, roda os testes unitários e os
Node.js Express API with TypeScript 3 Node.js Express API with TypeScript 3. Supports MongoDB Description This skeleton will help you to build your own Node.js Express Mongodb API using TypeScript 3.
Express & ES6 REST API Boilerplate This is a straightforward boilerplate for building REST APIs with ES6 and Express. ES6 support via babel REST resources as middleware via resource-router-middleware
express-mongodb-rest-api-boilerplate Also express-graphql-mongodb-boilerplate - GraphQL API Boilerplate Authentication from scratch Sign In, Sign Up, Reset Password, Change Password, Update User E-mai
Express & mongoose REST API Boilerplate in ES6 with Code Coverage Sponsor You can support the project by checking out our sponsor page. It takes only one click: Overview This is a boilerplate applicat
Node boilerplate This is my node boilerplate starter kit. I will continue to update with the latest tech to help make make node servicessuper easy and efficient to kick start. Whats out the box? Frame