[Перевод] Разработка REST API на Express, Restify, hapi и LoopBack
Если вы работаете над Node.js приложением, то есть все шансы, что у него появится некое API, которое будет использовано вами или кем-то другим. Наверняка это будет REST API и перед вами возникнет дилемма — какие инструменты и подходы использовать. Ведь выбор так широк…
Благодаря невероятно активному сообществу Node.js, количество результатов на NPM по запросу «rest» зашкаливает. У каждого есть свои реализации и подходы, но у некоторых есть что-то общее в создании REST API на Node.js.
Express
Наиболее распространённый подход — дать доступ к ресурсам с помощью Express. Это даст лёгкий старт, но в последствии будет становиться всё более тяжелым.Пример
Используя Router последней версии Express 4.x, ресурс будет выглядеть примерно так:
var express = require ('express');
var Item = require ('models').Item;
var app = express ();
var itemRoute = express.Router ();
itemRoute.param ('itemId', function (req, res, next, id) {
Item.findById (req.params.itemId, function (err, item) {
req.item = item;
next ();
});
});
itemRoute.route ('/: itemId')
.get (function (req, res, next) {
res.json (req.item);
})
.put (function (req, res, next) {
req.item.set (req.body);
req.item.save (function (err, item) {
res.json (item);
});
})
.post (function (req, res, next) {
var item = new Item (req.body);
item.save (function (err, item) {
res.json (item);
});
})
.delete (function (req, res, next) {
req.item.remove (function (err) {
res.json ({});
});
})
;
app.use ('/api/items', itemRoute);
app.listen (8080);
Плюсы
Минусы
Низкий порог вхождения, Express — это практически стандарт Node.js-приложения.
Полная кастомизация.
Все ресурсы необходимо создавать вручную и, в результате, появится много повторного кода или хуже — собственная библиотека.
Каждый ресурс требует тестирования или простой проверки на 500-ую ошибку.
Рефакторинг станет болезненным, так как будет необходимо править всё и везде.
Нету стандартного подхода, нужно искать свой.
Express — это отличный старт, но в итоге вы почувствуете боль от «своего собственного» подхода.Restify
Restify — относительно старый игрок на поле Node.js API, но очень стабильный и активно разрабатываемый. Он создан для построения правильных REST-сервисов и намеренно похож на Express.Пример
Так как он похож на Express, то и синтаксис практически такой же:
var restify = require ('restify');
var Item = require ('models').Item;
var app = restify.createServer ()
app.use (function (req, res, next) {
if (req.params.itemId) {
Item.findById (req.params.itemId, function (err, item) {
req.item = item;
next ();
});
}
else {
next ();
}
});
app.get ('/api/items/: itemId', function (req, res, next) {
res.send (200, req.item);
});
app.put ('/api/items/: itemId', function (req, res, next) {
req.item.set (req.body);
req.item.save (function (err, item) {
res.send (204, item);
});
});
app.post ('/api/items/: itemId', function (req, res, next) {
var item = new Item (req.body);
item.save (function (err, item) {
res.send (201, item);
});
});
app.delete ('/api/items/: itemId', function (req, res, next) {
req.item.remove (function (err) {
res.send (204, {});
});
});
app.listen (8080);
Плюсы
Минусы
Поддержка DTrace, если API работает на платформе, которая его поддерживает.
Нет такого лишнего функционала, как шаблоны и рендеринг.
Ограничение частоты запросов (throttling).
Поддержка SPDY
Минусы такие же как и у Express — много лишней работы.
hapi
hapi — менее известный фреймворк, который разрабатывается командой Walmart Labs. В отличие от Express и Restify у него несколько другой подход, предоставляющий больший функционал сразу из коробки.Пример
var Hapi = require ('hapi');
var Item = require ('models').Item;
var server = Hapi.createServer ('0.0.0.0', 8080);
server.ext ('onPreHandler', function (req, next) {
if (req.params.itemId) {
Item.findById (req.params.itemId, function (err, item) {
req.item = item;
next ();
});
}
else {
next ();
}
});
server.route ([
{
path: '/api/items/{itemId}',
method: 'GET',
config: {
handler: function (req, reply) {
reply (req.item);
}
}
},
{
path: '/api/items',
method: 'PUT',
config: {
handler: function (req, reply) {
req.item.set (req.body);
req.item.save (function (err, item) {
res.send (204, item);
});
}
}
},
{
path: '/api/items',
method: 'POST',
config: {
handler: function (req, reply) {
var item = new Item (req.body);
item.save (function (err, item) {
res.send (201, item);
});
}
}
},
{
path: '/api/items/{itemId}',
method: 'DELETE',
config: {
handler: function (req, reply) {
req.item.remove (function (err) {
res.send (204, {});
});
}
}
}
]);
server.start ();
Плюсы
Минусы
Полный контроль над приёмом запросов.
Детальная справка с генерацией документации.
hapi, также как Express и Restify, даёт отличные возможности, но как их использовать, вы должны понять сами.
Express, Restify и hapi отличные решения для старта, но, если вы планируете развивать API, то они могут стать плохим выбором.
LoopBack
LoopBack от StrongLoop — это полноценный Node.js-фреймворк для соединения приложений с данными через REST API. Он перенимает мантру «договорённость в конфигурации», ставшей популярной в Ruby on Rails.Пример
var loopback = require ('loopback');
var Item = require ('./models').Item;
var app = module.exports = loopback ();
app.model (Item);
app.use ('/api', loopback.rest ());
app.listen (8080);
Много волшебства происходит за кулисами, но всего шесть строчек кода создадут для вас эти ресурсы:
GET /items
GET /items/count
GET /items/findOne
GET /items/{id}
GET /items/{id}/exists
POST /items
PUT /items
PUT /items/{id}
DELETE /items/{id}
Чтобы легко изучить свой API, достаточно подключить встроенный модуль explorer:
var explorer = require ('loopback-explorer');
app.use ('/explorer', explorer (app, {basePath: '/api'}));
Теперь откройте localhost:8080/explorer и получите эту крутую документацию: 
Пример на LoopBack достаточно простой, но что на счёт RPC-ресурса?
var loopback = require ('loopback'); var explorer = require ('loopback-explorer'); var remoting = require ('strong-remoting'); var Item = require ('./models').Item; var app = module.exports = loopback (); var rpc = remoting.create (); function echo (ping, callback) { callback (null, ping); } echo.shared = true; echo.accepts = {arg: 'ping'}; echo.returns = {arg: 'echo'}; rpc.exports.system = { echo: echo }; app.model (Item); app.use ('/api', loopback.rest ()); app.use ('/explorer', explorer (app, {basePath: '/api'})); app.use ('/rpc', rpc.handler ('rest')); app.listen (8080); Теперь можно делать так:
$ curl «http://localhost:8080/rpc/system/echo? ping=hello»
{
«echo»: «hello»
}

Плюсы Минусы Очень быстрая разработка REST API. Договорённость в конфигурации. Встроенные готовые модели. Поддержка RPC. Полностью настраиваемый. Обширная документация. Команда, работающая над проектом на постоянной основе и являющаяся основной компанией-контрибутором в Node.js. Коммерческая поддержка. Порог вхождения немного высок, так как фреймворк состоит из множества деталей. Что дальше
