Skip to content

🏇 Lightweight, minimalistic approach to fully functioning RESTful endpoints.

License

Notifications You must be signed in to change notification settings

jackrobertscott/hobson-180221

Repository files navigation

hobson

Lightweight, minimalistic approach to RESTful endpoints in express.

Build Status npm version PRs Welcome License: MIT

Get up and running with a fully functioning CRUD API, with minimum configuration. Get all the functionality of a fully loaded framework with only the smallest amount of configuration.

Highlights

The hobson framework follows a RESTful approach. It uses models to define database relations and resources to provide endpoints to query the database.

  • Provides commonly used CRUD endpoints out of the box
  • Easily add and configure endpoints
  • Endpoints take a protected by default approach to ensure security
  • Provides stateless authentication using tokens
  • Mongoose is used to provide great schema validation, hooks, etc.
  • Before and after hooks are provided
  • Easily integrates with existing express apps

Install

Get started by installing hobson.

npm install --save hobson

Hobson uses mongoose under the hood as it gives us awesome schema validation features.

Usage

Hobson is straight forwards in that it has 2 main types of components; models and resources. Models handle data interations and resources provide easy to use API endpoints.

Step 1. Create a model with a schema

File: unicorn.model.js

const { Schema } = require('hobson');

const unicornSchema = Schema({
  shape: {
    owner: {
      type: mongoose.Schema.ObjectId,
      ref: 'User', // same as userResource.name
      required: true,
    },
    name: {
      type: String,
      required: true,
    },
  },
  options: {
    timestamps: false,
  },
});

// unicornSchema is a mongoose schema which means you can create virtuals, methods, etc. on it.

unicornSchema.virtual('today').get(() => Date.now());

module.exports = unicornSchema.compile('Unicorn'); // returns the Unicorn model

Step 2. Create a resource from a model

File: unicorn.resource.js

const { Resource } = require('hobson');
const Unicorn = require('./unicorn.model.js');

const unicornResource = new Resource({ model: Unicorn });

// route configuration here...

module.exports = unicornResource;

Step 3. Connect to your express app

File: app.js

const hobson = require('hobson');
const app = require('express')();

// add middlewares and configurations to express app...

hobson.attach({
  app,
  secret: process.env.SUPER_SECRET_FOR_AUTHENTICATION,
  resources: [
    unicornResource,
    // others...
  ],
});

Endpoints

All endpoints have a unique string ID by which you can use to access them. To access an resource's endpoint, use the get method.

unicornResource.get('findById');

To overwrite an endpoint, simply provide your endpoint configuration with the same ID value.

CRUD Endpoints Provided

The hobson resource creates endpoints for you like you would on a regular RESTful API.

ID Method Endpoint Example
find get /unicorns /unicorns?filter[color]=purple
count get /unicorns/count /unicorns/count?filter[color]=yellow
findOne get /unicorns/one /unicorns/one?include=horns
findById get /unicorns/:unicornId /unicorns/5a8ed7fabf4aabad60e41247
create post /unicorns /unicorns
update patch /unicorns/:unicornId /unicorns/5a8ed7fabf4aabad60e41247
remove delete /unicorns/:unicornId /unicorns/5a8ed7fabf4aabad60e41247

Custom Endpoints

Here is how you add custom endpoints to the resource.

File: unicorn.resource.js

const findGreenUnicons = new Route({
  id: 'findGreenUnicons',
  path: '/green',
  methods: 'get',
  handler: async () => console.log('do things here'),
});

unicornResource.add(findGreenUnicorns);

Authentication

Routes are protected by default. Provide permission functions to give access to your users.

File: unicorn.resource.js

unicornResource.get('findGreenUnicorns')
  .access(({ user }) => {
    return user.role === ROLE_ADMIN; // access given to only admins
  });

Logic & Hooks

Provide hooks to your endpoints which will run before and after the main handler. There is also a helpful context object which you can use to assign data to access throughout your function chain.

File: unicorn.resource.js

unicornResource.get('findGreenUnicorns')
  .before(({ context }) => {
    context.appendMessage = 'Hi Fred,';
  })
  .after(({ data, context }) => {
    console.log(context.appendMessage, data); // Hi Fred, Yo mama!
  });

You can also use old express middleware too. When added, these will run before all the other functions.

File: unicorn.resource.js

unicornResource.get('findGreenUnicorns')
  .middleware((req, res, next) => {
    req.example = 'Hello there!';
    next(); // important: make sure to call next
  });

Response Standards

Endpoints should return information in a specific format so that it is easy to read on the client.

The following standards are inspired by the work done on JSend. See there standards here.

Success

{
  "status": "success",
  "code": 200,
  "data": {
    "unicorns": [
      {
        "_id": "110297391319273",
        "content": "This is a good unicorn.",
      },
      {
        "_id": "110297391319273",
        "content": "This is another unicorn.",
      }
    ],
  }
}

Failed

{
  "status": "fail",
  "code": 400,
  "message": "There was a validation error.",
  "data": {
    "title": {
      "message": "Path `title` is required.",
      "kind": "required",
      "path": "title",
    },
    "magic.wands": {
      "message": "Path `magic.wands` (10) is less than minimum allowed value (1000).",
      "kind": "min",
      "path": "magic.wands",
      "value": 10,
    }
  }
}

Error

{
  "status": "error",
  "code": 500,
  "message": "The server pooped itself.",
}

Maintainers

License

MIT

About

🏇 Lightweight, minimalistic approach to fully functioning RESTful endpoints.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published