npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

bookshelf-api

v1.7.1

Published

Express middleware for generating an API based on bookshelf models.

Downloads

72

Readme

bookshelf api

Custom URLS | Options | Where clauses | Fetching related models | Ordering results

Bookshelf API is configurable Express middleware that allows you to serve a RESTful API from a directory of Bookshelf.js models.

npm install --save bookshelf-api

Here's the basic usage:

let express = require('express');
let path = require('path');
let api = require('bookshelf-api')({
	path: './models' // relative to the current directory
});

let app = express();
app.use('/api/v1', api);

This simple setup will provide you with your standard GET, POST, PUT and DELETE verbs for a RESTful API based on the Bookshelf models in your ./models directory.

For example, imagine you have a product model that looks like this:

./models/Product.js
module.exports = bookshelf.Model.extend({
  tableName: 'products'
});

Using the setup above you will now be able to make API requests to /api/v1/product.

  • GET /api/v1/product - List all of the products.
  • GET /api/v1/product/23 - Get the product with id 23.
  • POST /api/v1/product - Create a new product
  • PUT /api/v1/product/7 - Update product with an id of 7.
  • DELETE /api/v1/product/83 - Delete the product with an id of 83.

You can find a full working example in the example directory.

Custom URLs

If you need more fined grained control over the URL format of your API, Bookshelf API allows you to specify customized URL formats. Consider the following example:

let express = require('express');
let path = require('path');
let api = require('bookshelf-api')({
	path: './models'
});

let app = express();
app.get('/api/v1/auth/all', api('User'));
app.get('/api/v1/auth/:id/details', api('User'));
app.post('/api/v1/auth', api('User'));

You may pass a [string] model name (this should match the file name of your model) into the middleware to ensure that the matched route will only interact with that specified model. You can use :id in your parameterized route to specify how to interact with a single model of the specified type.

Options

Bookshelf API also provides a number of options that allow you to customize the behavior of the API. They should be passed in to the middleware:

let options = {
	path: './models',
	putBehavior: 'update',
	hardDelete: true,
	deletedAttribute: 'deletedAt',
	pluralEndpoints: true,
	errors: {
		...
	}
}
let api = require('bookshelf-api')(options);

Below you will find a list of the available options and their behavior:

path

A string representing the path where the bookshelf models directory is located. This can be either an absolute path or a path relative to the directory of the calling script.

let path = require('path');
let options = {
	path: path.join(__dirname, 'models/bookshelf')
}
let api = require('bookshelf-api')(options);
putBehavior

default: 'upsert'

A string representing how PUT requests should behave. The options are update or upsert.

  • update - PUT requests will only update an existing record. If that record doesn't exist then the API will return a 404 not found error.
  • upsert - PUT requests will update existing records if they exist, or create new records if they do not exists, like a SQL UPSERT statement.
let options = {
	putBehavior: 'update'
}
let api = require('bookshelf-api')(options);
hardDelete

default: false

A boolean specifying if DELETE requests should be hard deletes. Hard deleted permanently remove the record from the database (SQL DELETE statement) whereas soft deletes will simply update a column specifying when that record was deleted. The record will still exist in the database but it will not appear anymore when you make GET requests.

If this option is false you should specify a column name that represents the datetime that the record was deleted (see deletedAttribute below).

let options = {
	hardDelete: true
}
let api = require('bookshelf-api')(options);
deletedAttribute

default: 'deletedAt'

This option is only relevant if the hardDelete option is false. This option specifies which column should keep track of when (if at all) a record was deleted.

let options = {
	hardDelete: true,
	deletedAttribute: 'delete_date'
}
let api = require('bookshelf-api')(options);
pluralEndpoints

default: false

This option allows you to change the default API endpoints that bookshelf-api sets up. By default, endpoints are singular (/product, /user, etc). Setting this option to true instead uses plural endpoints (/products, /users, etc).

let options = {
	pluralEndpoints: true
}
let api = require('bookshelf-api')(options);
errors

This option allows you to override the default error messages that bookshelf api gives when there are bad requests or records are not found. The default error messages can be found in src/errors/js.

This option should provide overides for one or more of these errors if you want more control over the wording of your error messages.

let options = {
	errors: {
		UNKNOWN: {
			message: 'Something bad happened!',
			status: 500
		},
		RECORD_NOT_FOUND: {
			message: 'The {{ model }} you are looking for doesn\'t exist. id = {{ id }}.',
			status: 404
		}
	}
}
let api = require('bookshelf-api')(options);

Where clauses

The Bookshelf API module supports querying the API via where clauses in the query parameters of your GET requests. There are two supported formats:

Object format

$.ajax({
	url: '/api/v1/products',
	method: 'get',
	accepts: 'application/json',
	data: {
		// Queries all products where the price is 234
		// and the name is 'Pants'
		where: {
			price: 234,
			name: 'Pants'
		}
	}
});

Array format

$.ajax({
	url: '/api/v1/products',
	method: 'get',
	accepts: 'application/json',
	data: {
		// Queries all products where the price is
		// greater than 100
		where: ['price', '>', 100]
	}
});

Some other operators for Array format

  • Not equal: ['price', '<>', 0]
  • Like: ['name', 'LIKE', 'Hat%']
  • Not Like: ['name', 'NOT LIKE', 'Hat%']

Fetching related models

The Bookshelf API module supports querying related models.

$.ajax({
	url: '/api/v1/products/1',
	method: 'get',
	accepts: 'application/json',
	data: {
		// Queries the product with id 1 and includes
		// the associated manufacturer
		withRelated: ['manufacturer']
	}
});

This works when querying both single records and lists of records and depnds on your Bookshelf models being configured correctly. For example, your models for the above example might look like:

Product.js

require('./Manufacturer');
module.exports = bookshelf.model('Product', {
	tableName: 'products',
	hasTimestamps: ['createdAt', 'updatedAt', 'deletedAt'],
	manufacturer: function() {
		return this.belongsTo('Manufacturer', 'manufacturerId');
	}
});

Notice that the Product model has a manufacturer method. This is how the withRelated array knows how to associate a manufacturer with the product.

Manufacturer.js

module.exports = bookshelf.model('Manufacturer', {
	tableName: 'manufacturers',
	hasTimestamps: ['createdAt', 'updatedAt', 'deletedAt']
});

Ordering results

When you make GET requests you can optionally specify a column to use for sorting the resulting records as well as a sort direction.

sort

The sort query parameter can be the name of any column on the model that you are querying.

direction

The direction query parameter can be either asc (for ascending order) or desc (for descending order).

Example

$.ajax({
	url: '/api/v1/products/1',
	method: 'get',
	accepts: 'application/json',
	data: {
		sort: 'price',
		direction: 'desc'
	}
});