
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
restful-api
Advanced tools
This package is now in use in a beta application. Expect some evolution still, though it is certainly ready for usage in apps now!
... if you would like to help, feel free to write some unit tests. ;)
REST. It's not just a bunch of letters and a vague way to get things done. It is a way of looking at interfacing with systems using nouns and verbs. Luckily, over HTTP, we have both! All we have to do is start structuring our requests in a grammatically correct way. The result is faster development, easier maintenance and an all around better way to build APIs.
Here are a quick battery of RESTful APIs for a Blog "Post" Resource:
GET /posts // Returns a list of all posts available!
POST /posts // Creates a new post!
GET /posts/1 // Returns a single post!
PUT /posts/1 // Updates a post that exists!
DELETE /posts/1 // Deletes a post that exists!
It should become fairly obvious why there are so many advantages of this style; Convention over configuration. Powerful simplicity. Best of all, it's more or less become the standard API style over the web. No assumptions are made (in this framework) about your applications general structure. Security is strongly supported in each resource, but you can still structure your app as you like. It is recommended that you follow REST guidelines and make it possible for each individual request to require authorization, rather than relying purely on sessions.
One of the few downfalls of REST is the lack of batch APIs. Continuing the Blog example, want to delete 80 posts? Good luck. Make 80 calls to the API. This library attempts to solve that problem on a larger scale, too. But you shouldn't have to write any extra code. It will look to your code as if 80 separate calls were made (if you use the batch functionality of this library).
POST /posts/batch
Body: { 'delete': [1, 2, 3, 4, 5, 10, 42, 68, 99] }
The result? Returns an array of response objects, just as if you had made all 9 calls individually! Need to make an update call for a whole bunch of posts at a time? Create a bunch? Easy peasy:
POST /posts/batch
Body: { 'update': { 1: { title: 'My new title!' }, 2: { author: 'Walter White' } } }
POST /posts/batch
Body: { 'create': [{ name: 'New post!', body: 'Some stuff..' }, { name: 'Another...', body: 'This is nifty!'}] }
None of the available REST libraries did what I wanted. They were either too obscure, not well documented enough, or just flat out got REST wrong. My goals for this project are:
npm install restful-api --save
First you have to require the restful-api, at some point after your express initialization.
var rest = new require('restful-api')(app); // where 'app' is your express application.
There is a second parameter available as a default override. Lets say you decided to call your indices 'list' instead of 'index'. You could apply that as default across your app in one fell swoop, like so:
var rest = new require('restful-api')(app, { index: 'list' })
For more info on defaults, take a look at restful-api/lib/defaults.js
This isn't obvious when you first look at it, but will become more understandable when you get to Step 5 (where "Controller" is explained).
rest.register_controller('posts', PostsController)
or, if you would prefer to regisgter multiple at once...
rest.register_controller({ 'posts': PostsController, 'comments': CommentsController })
The first parameter in the registering of the controller (Step 3) is the what you use as parameters, here.
rest.resource('posts') // <-- Produces /posts pathing!
rest.resource('posts', 'comments') // <-- Produces /posts/:post_id/comments pathing! ..hang tight for more info on this.
The last parameter may be used for overriding defaults, just the same way as mentioned in Step 2. Ex:
rest.resource('posts', { read: 'show' }) // uses the 'show' function on the Controller, instead of the 'read' function.
Any name that you registered can be added to the options object, plus '_resource', and given a value that you prefer. For example...
rest.resource('posts', 'comments', {posts_resource: 'articles', comments_resource: 'blathers'})
Thus setting up your routing to /articles/:article_id/blathers instead of /posts/:post_id/comments.
You can also add specific actions for your controller!
// add a GET route for /posts/blather that will be passed to 'blather' in your controller with all filters applied.
res.resouce('posts', { list_actions: [{http_verb: 'get', controller_action: 'blather'}] })
// add a GET route for /posts/:post_id/blather that will be passed to 'blather' in your controller with all filters applied.
res.resource('posts', { individual_actions: [{http_verb: 'get', controller_action: 'blather'}] })
These are the properties and callbacks that a controller may have on it. All callbacks are the last arg of the function signature, and they all follow the node convention of callback(err, args...).
PostsController = {
// identifier is a string that was passed in the URI.
// is_index is a boolean for if this was called from an index or not
// callback takes err and the model. the model will be set on the request object for subsequent requests (pluralized when index, singularized when not).
finder: function (req, identifier, is_index, callback) {},
// is_nested indicates whether this controllers action will be called.
// is_secure_callback takes err and a boolean to indicate if the request is authorized.
secure: function (req, is_nested, is_secure_callback) {},
// filters that are run before the resource function. Callback takes err.
before_filters: [ function (req, res, callback) ],
// filters that are run after the resource function, and after the response has been sent. Callback takes err.
after_filters: [ function (req, res, callback) ],
// ** Actions: These are the actually heavy lifters of a resource.
// data is a callback that accepts error and an array of serializable objects. Each object must contain an 'id' property.
index: function (req, res, data) {},
// data is a callback that accepts error and a serializable object. Must contain on 'id' property.
read: function (req, res, data) {},
// data is a callback that takes error and a serializable version of the created resource. Must contain an 'id' property.
create: function (req, res, data) {},
// data is a callback that takes error and a serializable version of the updated resource. Must contain an 'id' property.
update: function (req, res, data) {},
// success is a callback that takes error. If there isn't one, it returns 200 to indicate success.
remove: function (req, res, success) {}
}
Note that if you omit any of these, it doesn't matter! They're simply not applied to that particular resource. Missing a finder? No biggy. No security necessary? Omit the secure property. Don't need an index? Don't use it! That simple. Oh, and if you omit an action, a proper 405 will be returned by default.
Nested Controllers: When you nest your controllers (say, posts/comments), only the action of the final controller is called. But the finder and secure filters are run on every single controller, from left to right. That means that if you lock down a posts controller, it'll apply all the way down the line. Make sure you make use of the is_nested boolean so that you don't unnecessarily lock down controllers that are further down the execution path!
Batch API: When you use the batch API, you are running the final resources finder, secure, filters, and action, multiple times, with different identifiers for finder each time. So you don't have to change anything in order to deal with those batches.
...yup, that's it! It's that easy. And now, you'll have an amazingly easy way to build APIs quickly and efficiently.
There is an issue tracker associated with this library on github. Please feel free to open an issue if you feel that something is incorrect, or come find me on twitter: @crueber.
FAQs
RESTful APIs via Convention.
We found that restful-api demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.