Skip to content

Instantly share code, notes, and snippets.

@BinaryMuse
Last active March 17, 2019 08:22
Show Gist options
  • Star 50 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save BinaryMuse/a57ae1a551472e06b29a to your computer and use it in GitHub Desktop.
Save BinaryMuse/a57ae1a551472e06b29a to your computer and use it in GitHub Desktop.
Express API with Async/Await
import express from "express";
/**
* Takes a route handling function and returns a function
* that wraps it after first checking that the strings in
* `reserved` are not part of `req.body`. Used for ensuring
* create and update requests do not overwrite server-generated
* values.
*/
function checkReservedParams(routeHandler, ...reserved) {
return function(req, res, next) {
for (let reservedKey of reserved) {
if (req.body[reservedKey]) {
return res.status(400).json({
error: `Cannot specify ${reservedKey} as part of request body`
});
}
}
routeHandler(req, res, next);
}
}
/**
* Takes a route handling function and returns
* a function that wraps it in a `try/catch`. Caught
* exceptions are forwarded to the `next` handler.
*/
function errorChecking(routeHandler) {
return async function (req, res, next) {
try {
await routeHandler(req, res, next);
} catch (err) {
next(err);
}
}
}
/**
* Takes a Sequelize model class and returns an Express
* router that provides a standard set of RESTful resource
* routes.
*/
export default function restful(model) {
async function index(req, res, next) {
const { offset = 0, limit = 10, orderBy = "createdAt", orderDirection = "ASC" } = req.query;
const result = await model.findAndCountAll({
offset, limit,
order: [ [orderBy, orderDirection] ]
});
res.json({
offset, limit, orderBy, orderDirection,
count: result.count,
data: result.rows
});
}
async function create(req, res, next) {
const instance = await model.create(req.body);
res.status(201).json({data: instance});
}
async function get(req, res, next) {
const instance = await model.findOne({
where: { id: req.params.id }
});
if (instance) {
res.json({data: instance});
} else {
res.status(404).json({error: "Not found"});
}
}
async function update(req, res, next) {
const instance = await model.findOne({
where: { id: req.params.id }
});
if (instance) {
const updated = await instance.updateAttributes(req.body);
res.json({data: updated});
} else {
res.status(404).json({error: "Not found"});
}
}
async function destroy(req, res, next) {
const instance = await model.findOne({
where: { id: req.params.id }
});
if (instance) {
await instance.destroy();
res.status(204).json({});
} else {
res.status(404).json({error: "Not found"});
}
}
function notAllowed(req, res) {
res.status(405).json({error: "Method not allowed"});
}
const router = express.Router();
router.route("/")
.get(errorChecking(index))
.post(errorChecking(checkReservedParams(create, "id", "createdAt", "updatedAt")))
.all(errorChecking(notAllowed));
router.route("/:id")
.get(errorChecking(get))
.put(errorChecking(checkReservedParams(update, "id", "createdAt", "updatedAt")))
.delete(errorChecking(destroy))
.all(errorChecking(notAllowed));
return router;
}
@darkamenosa
Copy link

You really saved my day!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment