REST
API - способ доступа к программному продукту
SOAP - запаковка в текстовый формат(XML) и удаленный вызов процедуры REST - архитектурный стиль для построения сетевых архитектур
- client-server
- запросы без состояний (запросы должны быть независимы с полной информацией)
- кэширование
- однообразный интерфейс
- многослойная система (всякие кеширующие сервера, прокси и т.д.)
- доставка кода по требованию (обновление кода по http протоколу) - на практике нет
Суть http протокола:
Открываем соединение, отправляем некоторые текстовые данные, закрываем соединение (request, response)
curl https://api.github.com --verbase
Нестандартные заголовки помечаются X- в начале
URI - unique resource identifier
Level 0 - используем http как транспорт, перекидываемся текстом, статус всегда 200, даже ошибка завернута в текст
Level 1 - то же + ресурсы доступны uri
Level 2 - add more HTTP stuff, для логики используем http коды
Level 3 - all links and make data live
Hypermedia or HATEOAS
- HAL
- Siren
- JSON API
Express
var express = require('express');
var app = express();
app.get('/', function(req, res) {
res.send('Hello World!');
});
app.listen(3000, function() {
console.log('Example app listening on port 3000');
});
app.get('/users/:userId', function(req, res) {});
// users.js
let userRouter = express.Router();
// items.js
let itemRouter = express.Router();
// app.js
import userRouter from './users';
import itemRouter from './item';
app.use('/users', userRouter);
app.use('/items', itemRouter);
Middleware - функции с 3 или 4 параметрами, которые обрабатывают наш запрос
function printMethod(req, res, next) {
console.log('Method is ', req.method);
next();
}
router.use('/', validateToken, checkPermissions);
router.post('/users', [validateInput, handleUserCreate]);
Error handling
if(err) return next(err);
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
Protect your API
- use https (free now)
- authentication/authorization (passport.js)
- cors
- rate limit request
- ip whitelist
pm2 for build
Project structure
doc/
config/
migrations/ - изменения в бд в виде скриптов
routes/
services/ | models/
test/
unit/
api/
app.js
run.js
package.json
route grouping
- by features
- by consumers
- by versions of api
rootRouter.get(url.add("self", "/api/root"), (req, res, next) => {
res.apiResponse({
links: {
users: url.get("users"),
profile: url.get("profile")
}
});
});
versioning
client send req with header
Accept: application/vnd.mycompany.myapp-v2+json
rootRouter.get(url.add("self", "/api/root"), (req, res, next) => {
let mediaType = req.get('Accept');
res.apiResponse({
links: getLinks(mediaType)
});
});
Tests
Mocha + Supertest
describe('GET /users', function() {
it('respond with json', function(done) {
request(app)
.get('/users')
.set('Accept', 'application/json')
.expect(200)
.end(function(err, res) {
if (err) return done(err)
done()
})
})
it('should return array of users', function(done) {})
});
Tools
- ApiDoc
- Swagger
- Blueprint
- RAML
- GraphQL
- Meteor
- WebSockets