迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:aichbauer/express-rest-api-boilerplate开源软件地址:https://github.com/aichbauer/express-rest-api-boilerplate开源编程语言:JavaScript 100.0%开源软件介绍:express-rest-api-boilerplate
Table of ContentsInstall and UseStart 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. Folder StructureThis boilerplate has 4 main directories:
ControllersCreate a ControllerControllers in this boilerplate have a naming convention: 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; ModelsCreate a ModelModels in this boilerplate have a naming convention: 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; PoliciesPolicies 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.
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
}); auth.policyThe 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
}); ServicesServices 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; ConfigHolds all the server configurations. Connection and Database
This two files are the way to establish a connaction to a database. You only need to touch connection.js, default for
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 RoutesHere you define all your routes for your api. It doesn't matter how you structure them. By default they are mapped on Create RoutesFor further information read the docs of express-routes-mapper. Example for User Model:
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)); TestAll test for this boilerplate uses Jest and supertest for integration testing. So read their docs on further information. SetupThe setup directory holds the Controller
To test a Controller we create |
2022-08-15
2022-08-17
2023-10-27
2022-09-23
2022-08-13
请发表评论