10 найкращих практик написання API REST Node.js

У цій статті ми висвітлюємо кращі практики написання API REST Node.js, включаючи такі теми, як іменування ваших маршрутів, автентифікація, тестування в чорному ящику та використання відповідних заголовків кешу для цих ресурсів.

Один з найпопулярніших випадків використання Node.js - це написання RESTful API, використовуючи його. Тим не менше, хоча ми допомагаємо нашим клієнтам знаходити проблеми у своїх програмах із Trace, за допомогою нашого інструменту моніторингу Node.js ми постійно відчуваємо, що у розробників багато проблем з API REST.

Я сподіваюся, що ці найкращі практики, які ми використовуємо в RisingStack, можуть допомогти:

№1: Використовуйте методи HTTP та маршрути API

Уявіть, що ви створюєте API RESTful для Node.js для створення, оновлення, отримання або видалення користувачів. Для цих операцій HTTP вже має відповідний набір інструментів: POST, PUT, GET, PATCH або DELETE.

Як найкраща практика, ваші маршрути API завжди повинні використовувати іменники як ідентифікатори ресурсів. Якщо говорити про ресурси користувача, то маршрутизація може виглядати так:

  • POST / user або PUT / user: / id для створення нового користувача,
  • GET / користувач, щоб отримати список користувачів,
  • GET / user /: id, щоб отримати користувача,
  • PATCH / user /: id для зміни існуючої записи користувача,
  • DELETE / user /: id, щоб видалити користувача.

№ 2: Правильно використовувати коди статусу HTTP

Якщо під час обслуговування запиту щось піде не так, ви повинні встановити правильний код статусу для цього у відповіді:

  • 2xx, якщо все було нормально,
  • 3xx, якщо ресурс було переміщено,
  • 4xx, якщо запит не може бути виконаний через помилку клієнта (наприклад, запит на ресурс, який не існує),
  • 5xx, якщо щось пішло не так на стороні API (як, наприклад, трапився виняток).

Якщо ви використовуєте Express, встановити код статусу так само просто, як res.status (500) .send ({помилка: 'Виникла внутрішня помилка сервера'}). Аналогічно з Restify: res.status (201).

Щоб отримати повний список, перегляньте список кодів статусу HTTP

№3: Використовуйте заголовки HTTP для надсилання метаданих

Для вкладення метаданих про корисне навантаження, яке ви збираєтеся надіслати, використовуйте заголовки HTTP. Такі заголовки можуть містити інформацію про:

  • пагинація,
  • обмеження ставки,
  • або автентифікація

Список стандартизованих заголовків HTTP можна знайти тут.

Якщо вам потрібно встановити будь-які власні метадані у своїх заголовках, найкращою практикою було приєднання їх за допомогою X. Наприклад, якщо ви використовували маркери CSRF, це був звичайний (але нестандартний) спосіб назвати їх X-Csrf -Взяв. Однак з RFC 6648 вони застаріли. Нові API повинні докласти максимум зусиль, щоб не використовувати імена заголовків, які можуть суперечити іншим програмам. Наприклад, OpenStack префіксує свої заголовки OpenStack:

OpenStack-Identity-Account-ID
OpenStack-Networking-Name-Host
OpenStack-Object-Storage-Policy

Зауважте, що стандарт HTTP не визначає жодного обмеження розміру на заголовках; однак, Node.js (станом на написання цієї статті) встановлює обмеження розміру 80 КБ на об’єкт заголовків з практичних причин.

"Не дозволяйте загальний розмір заголовків HTTP (включаючи рядок статусу) перевищувати HTTP_MAX_HEADER_SIZE. Ця перевірка знаходиться тут, щоб захистити вбудовувачі від атак відмови у наданні послуги, коли зловмисник подає нам нескінченний заголовок, що вбудовувач зберігає буферизацію ".
Від HTTP-аналізатора Node.js

# 4: Виберіть правильну основу для вашого Rode API Node.js

Важливо вибрати рамку, яка найбільше відповідає вашому використанню.

Експрес, Коа або Хапі

Express, Koa та Hapi можна використовувати для створення програм для браузерів, і вони підтримують шаблонування та рендерінг - лише щоб назвати кілька функцій. Якщо у вашій програмі також потрібно надати сторону, орієнтовану на користувачів, має сенс звернутися до них.

Виправити

З іншого боку, Restify зосереджується на допомозі у створенні REST-послуг. Це існує для того, щоб ви могли будувати «суворі» сервіси API, які є ретельними та спостережуваними. Restify також постачається з автоматичною підтримкою DTrace для всіх ваших обробників.

Restify використовується у виробництві в основних сферах застосування, таких як npm або Netflix.

№5: Black-Box Тестуйте свої API REST Node.js

Один з найкращих способів перевірити свої API REST - це трактувати їх як чорні поля.

Тестування в чорному ящику - це метод тестування, коли функціональність програми перевіряється без відома її внутрішніх структур чи функціонування. Тож жодна із залежностей не знущається і не заглушує, а система перевіряється в цілому.

Один з модулів, який може допомогти вам у тестуванні чорних скриньок API REST API - це супертест.

Простий тестовий випадок, який перевіряє, чи повертається користувач за допомогою тесту мокера тестового бігуна, може бути реалізований так:

const request = вимагати ("супертест")
 
description ('GET / user /: id', function () {
  it ('повертає користувача', функція () {
    // новіші версії мокко також приймають обіцянки
    запит на повернення (додаток)
      .get ('/ користувач')
      .set ('Прийняти', 'application / json')
      .очікуємо (200, {
        id: '1',
        ім'я: 'Джон Мат'
      }, готово)
  })
})

Ви можете запитати: як дані заповнюються в базу даних, яка обслуговує API REST?

Взагалі, це хороший підхід, щоб написати свої тести таким чином, щоб вони зробили якомога менше припущень про стан системи. Тим не менше, у деяких сценаріях ви можете опинитися в місці, коли вам потрібно точно знати, який стан системи, тож ви можете робити твердження і досягати більш високого покриття тесту.

Отже, виходячи з ваших потреб, ви можете заповнити базу даних тестовими даними одним із наступних способів:

  • запускайте свої сценарії тестування чорного поля на відомому підмножині виробничих даних,
  • заповнити базу даних створеними даними перед запуском тестових випадків.

Звичайно, тестування в чорному ящику не означає, що вам не потрібно робити тестування одиниць, вам все одно потрібно писати одиничні тести для своїх API.

№ 6: Робіть на основі JWT автентифікацію без громадянства

Оскільки ваші API REST повинні бути без стану, так і рівень аутентифікації. Для цього ідеально підходить JWT (JSON Web Token).

JWT складається з трьох частин:

  • Заголовок, що містить тип маркера та алгоритм хешування
  • Корисне навантаження, що містить претензії
  • Підпис (JWT не шифрує корисний вантаж, а лише підписує його!)

Додавання автентифікації на основі JWT дуже просто:

const koa = вимагати ('koa')
const jwt = вимагати ('koa-jwt')
додаток const = koa ()
app.use (jwt ({
  секрет: 'дуже таємний'
}))
// Захищене програмне забезпечення
app.use (функція * () {
  // вміст токена буде доступний на цьому веб-сайті this.state.user
  this.body = {
    секрет: '42'
  }
})

Після цього кінцеві точки API захищаються JWT. Для доступу до захищених кінцевих точок потрібно вказати маркер у полі заголовка авторизації.

curl --header "Авторизація: Носій eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwI
iwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30
RMHrHDcEfxjoYZgeFONFh7HgQ "my-website.com

Одне, що ви могли помітити, це те, що модуль JWT не залежить від будь-якого рівня бази даних. Це так, тому що всі жетони JWT можна перевірити самостійно, а також вони можуть містити час для живих значень.

Крім того, ви завжди повинні переконатися, що всі ваші кінцеві точки API доступні лише через безпечне з'єднання за допомогою HTTPS.

У попередній статті ми детально пояснили методи веб-аутентифікації - рекомендую перевірити!

№ 7: Використовуйте умовні запити

Умовні запити - це HTTP-запити, які виконуються по-різному в залежності від конкретних заголовків HTTP. Ви можете вважати ці заголовки як передумови: якщо вони будуть виконані, запити будуть виконані по-іншому.

Ці заголовки намагаються перевірити, чи відповідає версія ресурсу, що зберігається на сервері, даній версії того самого ресурсу. З цієї причини такими заголовками можуть бути:

  • часова мітка останньої модифікації,
  • або тег сутності, який відрізняється для кожної версії.

Ці заголовки:

  • Остання зміна (щоб вказати, коли ресурс востаннє змінено),
  • Етаг (для позначення тегу сутності),
  • If-Modified-Since (використовується із заголовком Останні зміни),
  • If-None-Match (використовується із заголовком Etag),

Давайте подивимось на приклад!

Клієнт нижче не мав жодних попередніх версій ресурсу doc, тому ні коли-небудь заголовок If-Modified-Since, ні If-None-Match не було застосовано. Потім сервер реагує правильно встановленими заголовками Etag та Last-Modified.

З документації про умовний запит MDN

Клієнт може встановити заголовки If-Modified-Since та If-None-Match, коли він намагається запросити той самий ресурс - оскільки у нього зараз є версія. Якщо відповідь буде однаковою, сервер просто відповідає статусом 304 - Not Modified і не надсилає ресурс знову.

З документації про умовний запит MDN

№ 8: Обмеження швидкості прийняття

Обмеження швидкості використовується для контролю кількості запитів, які може подати споживач до API.

Щоб повідомити користувачам API, скільки запитів у них залишилося, встановіть такі заголовки:

  • X-Rate-Limit-Limit - кількість запитів, дозволених за певний часовий інтервал
  • X-Rate-Limit - Залишається, кількість запитів, що залишаються в одному інтервалі,
  • X-Rate-Limit-Скидання, час, коли обмеження ставки буде скинуто.

Більшість фреймворків HTTP підтримують його нестандартно (або з плагінами). Наприклад, якщо ви використовуєте Koa, існує пакет koa-ratelimit.

Зауважте, що часове вікно може змінюватись залежно від різних постачальників API - наприклад, GitHub використовує годину для цього, а Twitter 15 хвилин.

№ 9: Створіть належну документацію API

Ви пишете API, щоб інші могли ними користуватися, отримувати користь від них. Забезпечення документації API для ваших API REST Node.js є вирішальним.

Наступні проекти з відкритим кодом можуть допомогти вам у створенні документації для ваших API:

  • План розробки API
  • Суегер

Крім того, якщо ви хочете використовувати продукти, що розміщуються, ви можете піти на Apiary.

№ 10: Не пропускайте майбутнє API

В минулі роки виникли дві основні мови запитів щодо API - а саме GraphQL від Facebook та Falcor від Netflix. Але навіщо вони нам навіть потрібні?

Уявіть наступний RESTful запит на ресурси:

/ org / 1 / space / 2 / docs / 1 / співпрацівники?
include = email & page = 1 & limit = 10

Це може вийти з рук досить легко - так як ви хочете отримувати однаковий формат відповідей для всіх своїх моделей постійно. Тут можуть допомогти GraphQL і Falcor.

Про GraphQL

GraphQL - це мова запитів для API та час виконання для виконання цих запитів із наявними даними. GraphQL надає повний і зрозумілий опис даних у вашому API, дає клієнтам можливість запитувати саме те, що їм потрібно, і нічого більше, полегшує еволюцію API з часом і дозволяє потужні інструменти для розробників. - Детальніше читайте тут.

Про Фалькор

Falcor - це інноваційна платформа даних, яка забезпечує користувальницькі інтерфейси Netflix. Falcor дозволяє моделювати всі ваші резервні дані як єдиний об’єкт Virtual JSON на сервері Node. На клієнті ви працюєте з віддаленим об’єктом JSON, використовуючи звичні операції JavaScript, такі як отримати, встановити та зателефонувати. Якщо ви знаєте свої дані, ви знаєте свій API. - Детальніше читайте тут.

Дивовижні API REST для натхнення

Якщо ви збираєтеся розпочати розробку API REST Node.js або створити нову версію старішої, ми зібрали чотири приклади реального життя, які варто перевірити:

  • GitHub API
  • API Twilio
  • API смуги
  • API DigitalOcean

Я сподіваюся, що тепер ви краще зрозумієте, як слід писати API за допомогою Node.js. Будь ласка, повідомте мене в коментарях, якщо ви щось пропустите!

Спочатку опубліковано на blog.risingstack.com 21 лютого 2017 року.