0.0.0 • Published 3 years ago

expressnap v0.0.0

Weekly downloads
-
License
ISC
Repository
-
Last release
3 years ago

ExpressNap

Expressnap is a small library enabling developers to rapidly build REST APIs using Sequelize ORM. It can be used in any exsisting express app using Sequelize.

Table of contents

Getting Started

To expose a sequelize model as a rest api, only one line of code is needed. The first parameter of the ApiBuilder class takes a string wihch will be used as a path for your express app. If 'users' is used, the API endpoint will be reachable under /users.

app.use(new ApiBuilder('users', UsersTable).build());

Here is a full example to just paste and run!

const ApiBuilder = require('expressnap');
//make sure to use body parser
const bodyParser = require('body-parser');
//other dependencies for this example
const express = require('express');
const { Sequelize, DataTypes, Model } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory:', {
    define: {
        freezeTableName: true,
        timestamps: false
    },
    logging: false
});

//define sequelize model class
class UsersTable extends Model { }
UsersTable.init({
    id: {
        type: DataTypes.INTEGER,
        allowNull: false,
        primaryKey: true,
        autoIncrement: true
    },
    age: {
        type: DataTypes.INTEGER,
    },
    name: {
        type: DataTypes.STRING,
    },
    has_email: {
        type: DataTypes.BOOLEAN
    }
}, { sequelize });

//create express app
let app = express();
app.use(bodyParser.json());


//this should be done better, just for demonstration!
(async () => {
    await UsersTable.sync({ force: true });

    //Expose sequelize model via rest api!
    app.use(new ApiBuilder('users', UsersTable).build());
})();

app.listen(3000, () => {
    console.log('listening on 3000');
})

Using the REST endpoint

Any exposed REST supports 4 operations using the http methods:

  • POST: create a new entity
  • PUT: update an existing entity
  • GET: retrieve (filtered) entities
  • DELETE: delete an entity

Limiting Actions

Sometimes, some actions should not be possible to perform for some endpoints. For example you might want a list to be only appendable and readable but entries should not be updateable or deleteable.

For this, you can disable the appropriate methods like this:

app.use(new ApiBuilder('users', UsersTable).disablePut().disableDelete().build());

All 4 operatione are on by default and can be disabled using these functions:

  • disableGet()
  • disablePost()
  • disablePut()
  • disableDelete()

Input validation and other configuration

You might ask yourself: How can I perform input validation when the api is automatically generated.

This is addressed using the setBeforeMiddleware((req,res,next)=>{}) function. It provides a standard express middleware function which is called before the API endpoint.

app.use(new ApiBuilder('users', UsersTable).setBeforeMiddleware((req, res, next) => {
    if(req.query.uid==1){
        res.status(401).send('no!');
    }else{
        next();
    }
}).build());

Similarly, output filtering on get requests can be performed using the setGetMapFunction((req,data)=>{}) function. It recieves the request object from express and a data array containing the query result. The data can be arbitrarily modified. The API endpoint will return the JSON of the return value of this function.

app.use(new ApiBuilder('getnames', UsersTable).setGetMapFunction((req,data)=>data.map(e=>e.name)).build());

If you want to perform actions after an element has been created, the setAfterCreateMiddleware((req,createdObject)=>{}) can be used.

app.use(new ApiBuilder('getnames', UsersTable).setAfterCreateMiddleware((req,createdObject)=>console.log(createdObject)).build());

Using the generated API

When fetching data from the API, the data can be filtered using the query parameters of the url. For example, if you want to retrieve all users that are 18 years old you can do something like this:

await fetch('/users',{method:'POST',headers:{'Accept': 'application/json','Content-Type': 'application/json'}, body:JSON.stringify({name:'max',age:18})});
const eighteenyearolds = await fetch('/users?age=18',{headers:{'Accept': 'application/json','Content-Type': 'application/json'}}).then(r=>r.json());

In POST, PUT and DELETE requests, the body and query parameters are automatically combined using Object.assign(req.query, req.body). This means, that body parameters are overwriting query parameters if a property is set in both.