Статьи

Знаете ли вы, что такое REST API?

REST — это аббревиатура от Transfer State State — почти бессмысленное описание наиболее используемой технологии веб-сервисов! REST — это способ для двух компьютерных систем взаимодействовать по HTTP аналогично веб-браузерам и серверам.

Обмен данными между двумя или более системами всегда был фундаментальным требованием разработки программного обеспечения. Например, рассмотрим покупку автострахования. Ваш страховщик должен получить информацию о вас и вашем транспортном средстве, чтобы они запрашивали данные у органов регистрации автомобилей, кредитных агентств, банков и других систем. Все это происходит прозрачно в режиме реального времени, чтобы определить, можно ли предложить политику.

Пример REST

Откройте следующую ссылку в вашем браузере, чтобы запросить случайную программную шутку:

https://official-joke-api.appspot.com/jokes/programming/random

Это общедоступный API, реализованный в виде веб-службы RESTful (соответствует соглашениям REST). Ваш браузер покажет ужасную шутку в формате JSON, такую ​​как:

[ { "id": 29, "type": "programming", "setup": "There are 10 types of people in this world...", "punchline": "Those who understand binary and those who don't" } ] 

Вы можете запросить тот же URL и получить ответ, используя любой HTTP-клиент, такой как curl :

 curl "https://official-joke-api.appspot.com/jokes/programming/random" 

Клиентские библиотеки HTTP доступны на всех популярных языках и во время выполнения, включая Fetch в JavaScript и file_get_contents () в PHP . Ответ JSON является машиночитаемым, поэтому его можно анализировать и выводить в HTML или любом другом формате.

Отдых и отдых

Различные стандарты передачи данных развивались на протяжении многих лет. Возможно, вы сталкивались со стандартами, включая CORBA , SOAP или XML-RPC , которые обычно устанавливали строгие правила обмена сообщениями.

REST был определен в 2000 году Роем Филдингом и значительно проще. Это не стандарт, а набор рекомендаций и ограничений для веб-сервисов RESTful. Это включает:

  1. Клиент-Сервер . SystemA отправляет HTTP-запрос на URL-адрес, размещенный SystemB, который возвращает ответ.

    Это идентично тому, как работает браузер. Приложение делает запрос на конкретный URL. Запрос направляется на веб-сервер, который возвращает HTML-страницу. Эта страница может содержать ссылки на изображения, таблицы стилей и JavaScript, которые вызывают дальнейшие запросы и ответы.

  2. Без гражданства . REST не имеет состояния: запрос клиента должен содержать всю информацию, необходимую для ответа на запрос. Другими словами, должна быть возможность сделать два или более HTTP-запроса в любом порядке, и будут получены те же самые ответы.

  3. Кешируемый Ответ должен быть определен как кешируемый или нет.

  4. Слоистый Запрашивающему клиенту не нужно знать, взаимодействует ли он с реальным сервером, прокси или любым другим посредником.

Создание веб-службы RESTful

Запрос веб-службы RESTful содержит:

  1. URL-адрес конечной точки . Приложение, реализующее API RESTful, определит одну или несколько конечных точек URL с доменом, портом, путем и / или строкой запроса — например, https://mydomain/user/123?format=json .

  2. Метод HTTP . Различные методы HTTP можно использовать на любой конечной точке, которая сопоставляется с операциями создания, чтения, обновления и удаления (CRUD) приложения:

    HTTP метод CRUD действие
    ПОЛУЧИТЬ читать возвращает запрошенные данные
    ПОЧТА Создайте создает новую запись
    Положить или патч Обновить обновляет существующую запись
    УДАЛЯТЬ удалять удаляет существующую запись

    Примеры:

    • запрос GET для /user/ возвращает список зарегистрированных пользователей в системе
    • запрос POST к /user/123 создает пользователя с идентификатором 123 с использованием данных тела
    • запрос PUT для /user/123 обновляет пользователя 123 данными тела
    • запрос GET к /user/123 возвращает данные пользователя 123
    • запрос DELETE к /user/123 удаляет пользователя 123
  3. Заголовки HTTP . Такая информация, как токены аутентификации или файлы cookie, может содержаться в заголовке HTTP-запроса.

  4. Данные тела . Обычно данные передаются в теле HTTP идентично отправке HTML <form> или путем отправки одной строки данных в кодировке JSON.

Ответ

Полезная нагрузка ответа может быть любой практической: данные, HTML, изображение, аудиофайл и т. Д. Ответы на данные, как правило, кодируются в формате JSON, но можно использовать XML, CSV, простые строки или любой другой формат. Вы можете разрешить указывать формат возврата в запросе — например, /user/123?format=json или /user/123?format=xml .

Соответствующий код состояния HTTP также должен быть установлен в заголовке ответа. 200 OK чаще всего используется для успешных запросов, хотя 201 Created также может быть возвращено при создании записи. Ошибки должны возвращать соответствующий код, такой как 400 Bad Request , 404 Not Found , 401 Unauthorized и так далее.

Могут быть установлены другие заголовки HTTP, включая директивы Cache-Control или Expires, чтобы указать, как долго может кэшироваться ответ, прежде чем он будет считаться устаревшим .

Однако строгих правил нет. URL-адреса конечных точек, методы HTTP, данные тела и типы ответов могут быть реализованы по вашему желанию. Например, POST, PUT и PATCH часто используются взаимозаменяемо, поэтому любой из них создаст или обновит запись.

Пример отдыха «Hello World»

В следующем коде создается веб-служба RESTful с использованием инфраструктуры Node.js Express . Одиночная /hello/ конечная точка отвечает на запросы GET.

Убедитесь, что у вас установлен Node.js , затем создайте новую папку с именем restapi . Создайте новый файл package.json в этой папке со следующим содержимым:

 { "name": "restapi", "version": "1.0.0", "description": "REST test", "scripts": { "start": "node ./index.js" }, "dependencies": { "express": "4.17.1" } } 

Запустите npm install из командной строки, чтобы получить зависимости, затем создайте файл index.js со следующим кодом:

 // simple Express.js RESTful API 'use strict'; // initialize const port = 8888, express = require('express'), app = express(); // /hello/ GET request app.get('/hello/:name?', (req, res) => res.json( { message: `Hello ${req.params.name || 'world'}!` } ) ); // start server app.listen(port, () => console.log(`Server started on port ${port}`); ); 

Запустите приложение из командной строки, используя npm start и откройте http://localhost:8888/hello/ в браузере. В ответ на запрос GET отображается следующий JSON:

 { "message": "Hello world!" } 

API также допускает использование произвольного имени, поэтому http://localhost:8888/hello/everyone/ Return:

 { "message": "Hello everyone!" } 

REST-запросы на стороне клиента и CORS

Рассмотрим следующую HTML-страницу, запущенную в браузере по URL-адресу http://localhost:8888/ :

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>REST test</title> </head> <body> <script> fetch('http://localhost:8888/hello/') .then((response) => { return response.json(); }) .then((json) => { console.log(json); }); </script> </body> </html> 

Вызов fetch выполняет тот же API-запрос, и консоль браузера показывает Object { message: "Hello world!" } Object { message: "Hello world!" } как и следовало ожидать.

Однако предположим, что ваш веб-сервис RESTful теперь запущен в Интернете по адресу http://mydomain.com/hello/ . URL-адрес страницы JavaScript fetch() соответствующим образом изменяется, но открытие http://localhost:8888/ в браузере теперь возвращает консольную ошибку Cross-Origin Request Blocked .

В целях безопасности браузеры разрешают только вызовы XMLHttpRequest и Fetch API на стороне клиента в тот же домен, где размещена страница.

К счастью, обмен ресурсами между источниками (CORS) позволяет нам обойти это ограничение безопасности. Задание заголовка HTTP-ответа Access-Control-Allow-Origin сообщает браузерам о разрешении запроса. Он может быть установлен для определенного домена или * для всех доменов (сделано с помощью API Joke выше).

Поэтому код API веб-службы можно изменить, чтобы разрешить доступ из любого клиентского сценария, работающего в любом домене:

 // /hello/ GET request app.get('/hello/:name?', (req, res) => res .append('Access-Control-Allow-Origin', '*') .json( { message: `Hello ${req.params.name || 'world'}!` } ) ); 

Кроме того, функция промежуточного программного обеспечения Express.js может добавлять заголовок к каждому запросу конечной точки:

 // enable CORS app.use((req, res, next) => { res.append('Access-Control-Allow-Origin', '*'); next(); }); // /hello/ GET request // ... 

REST Challenges

Успех REST во многом связан с его простотой. Разработчики могут свободно реализовывать API-интерфейсы RESTful по своему усмотрению, но это может привести к дальнейшим проблемам.

Консенсус конечной точки

Рассмотрим следующие конечные точки:

  • /user/123
  • /user/id/123
  • /user/?id=123

Все допустимые параметры для выборки данных для пользователя 123 . Количество комбинаций увеличивается с увеличением сложности операций. Например, верните десять пользователей, чьи фамилии начинаются с «A» и работают на companyX, начиная с записи 51, когда они упорядочены по дате рождения в обратном хронологическом порядке.

В конечном счете, не имеет значения, как вы форматируете URL-адреса, но важна согласованность вашего API. Это может быть трудно достичь на больших кодовых базах со многими разработчиками.

Управление версиями API

Изменения API неизбежны, но URL-адреса конечных точек никогда не должны быть признаны недействительными, когда они используются внутренне и / или сторонними приложениями.

API часто версионируются, чтобы избежать проблем с совместимостью — таких как /2.0/user/123 supersedes /user/123 — но старая конечная точка остается активной. Однако это увеличивает рабочую нагрузку, поскольку поддерживается несколько API. Старые API могут быть в конечном итоге отменены, но процесс требует тщательного планирования.

Аутентификация

Показанный выше API шутки открыт : любая система может получить шутку без авторизации. Это не подходит для API, которые получают доступ к частным данным или разрешают запросы на обновление и удаление.

Клиентские приложения в том же домене, что и RESTful API, будут отправлять и получать файлы cookie, как и любой другой HTTP-запрос. (Обратите внимание, что Fetch() в старых браузерах требует установки параметра инициализации credentials .) Поэтому запрос API может быть проверен, чтобы убедиться, что пользователь вошел в систему и имеет соответствующие права.

Сторонние приложения должны использовать альтернативные методы авторизации. Общие параметры аутентификации включают в себя:

  1. Базовая аутентификация HTTP . Заголовок HTTP- Authorization содержащий имя пользователя в кодировке base64: строка пароля передается в заголовке запроса.
  2. API ключи . Стороннему приложению предоставляется разрешение на использование API путем выдачи ключа, который может иметь определенные права или быть ограниченным конкретным доменом. Ключ передается в каждом запросе в заголовке HTTP или в строке запроса.
  3. OAuth . Токен получается до того, как любой запрос может быть отправлен отправкой идентификатора клиента и, возможно, секрета клиента на сервер OAuth. Затем токен OAuth отправляется с каждым запросом API до истечения срока его действия.
  4. JSON Web Tokens (JWT) . Жетоны аутентификации с цифровой подписью надежно передаются как в заголовке запроса, так и в ответе.

Аутентификация API зависит от контекста использования. В некоторых случаях стороннее приложение считается другим зарегистрированным пользователем с определенными правами и разрешениями — например, при создании направлений из API карты. В других случаях стороннее приложение используется зарегистрированным пользователем и может получить доступ только к его данным — например, при получении содержимого или документов электронной почты.

Безопасность

RESTful API предоставляет другой путь для доступа к вашему приложению и управления им. Даже если это не интересная цель для взлома, клиент с плохим поведением может отправлять тысячи запросов каждую секунду и приводить к сбою вашего сервера.

Безопасность выходит за рамки данной статьи, но общие рекомендации включают в себя:

  • использовать HTTPS
  • использовать надежный метод аутентификации
  • использовать CORS для ограничения вызовов на стороне клиента конкретными доменами
  • обеспечить минимальную функциональность, то есть не создавать опции DELETE, которые не требуются
  • проверить все URL конечной точки и данные тела
  • избегать выставления токенов API в клиентском JavaScript
  • заблокировать доступ с неизвестных доменов или IP-адресов
  • блокировать неожиданно большие полезные нагрузки
  • учитывайте ограничение скорости — то есть запросы, использующие один и тот же токен API или IP-адрес, ограничены N в минуту
  • ответьте соответствующим кодом статуса HTTP и заголовком кэширования
  • регистрировать запросы и расследовать сбои.

Несколько запросов и ненужных данных

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

Рассмотрим RESTful API, который предоставляет доступ к данным автора и книги. Чтобы показать данные для 10 самых продаваемых книг, клиент должен:

  1. Запросите первую 10 /book/ детали, упорядоченные по количеству продаж (сначала топ-продавец). Ответ содержит список книг с каждым идентификатором автора.
  2. Выполните до 10 запросов /author/{id} для получения имени каждого автора.

Это известно как проблема N + 1 ; N запросов API должны быть сделаны для каждого результата в родительском запросе.

Если это общий случай использования, API RESTful можно изменить так, чтобы каждая возвращаемая книга содержала полные сведения об авторе, такие как их имя, возраст, страна, биография и т. Д. Он также может предоставить полную информацию об их других книгах — хотя это значительно увеличит полезную нагрузку ответа!

Чтобы избежать массовых ответов, API можно настроить так, чтобы можно было контролировать подробности об авторе — например ?author_details=basic — но количество опций может быстро ?author_details=basic толку.

GraphQL исправляет REST?

Эти загадки REST привели Facebook к созданию GraphQL — языка запросов веб-сервисов. Думайте об этом как о SQL для веб-сервисов; один запрос определяет, какие данные вам нужны и как вы хотите их вернуть.

GraphQL решает многие проблемы, возникающие в RESTful API. Тем не менее, немногие компании имеют проблемы, сравнимые с Facebook. Стоит рассмотреть GraphQL, как только ваш RESTful API выйдет за пределы простой отправной точки.

Ссылки REST и инструменты разработки

Существует множество инструментов, помогающих в разработке RESTful API на всех языках. Известные варианты включают в себя:

  • Swagger : множество инструментов, помогающих проектировать, документировать, макетировать, тестировать и контролировать API REST
  • Почтальон : RESTful API-приложение для тестирования
  • Почтальон : альтернатива Почтальону с открытым исходным кодом.

Существует также множество общедоступных API-интерфейсов REST для шуток, конвертации валют, геокодирования, правительственных данных и любой темы, которую вы можете придумать. Многие из них бесплатны, хотя некоторые требуют, чтобы вы подписались на ключ API или использовали другие методы аутентификации. Категоризованные списки включают в себя:

Попробуйте использовать несколько RESTful API в ваших собственных проектах, прежде чем внедрять свои собственные веб-сервисы.