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. Это включает:
-
Клиент-Сервер . SystemA отправляет HTTP-запрос на URL-адрес, размещенный SystemB, который возвращает ответ.
Это идентично тому, как работает браузер. Приложение делает запрос на конкретный URL. Запрос направляется на веб-сервер, который возвращает HTML-страницу. Эта страница может содержать ссылки на изображения, таблицы стилей и JavaScript, которые вызывают дальнейшие запросы и ответы.
-
Без гражданства . REST не имеет состояния: запрос клиента должен содержать всю информацию, необходимую для ответа на запрос. Другими словами, должна быть возможность сделать два или более HTTP-запроса в любом порядке, и будут получены те же самые ответы.
-
Кешируемый Ответ должен быть определен как кешируемый или нет.
-
Слоистый Запрашивающему клиенту не нужно знать, взаимодействует ли он с реальным сервером, прокси или любым другим посредником.
Создание веб-службы RESTful
Запрос веб-службы RESTful содержит:
-
URL-адрес конечной точки . Приложение, реализующее API RESTful, определит одну или несколько конечных точек URL с доменом, портом, путем и / или строкой запроса — например,
https://mydomain/user/123?format=json
. -
Метод HTTP . Различные методы HTTP можно использовать на любой конечной точке, которая сопоставляется с операциями создания, чтения, обновления и удаления (CRUD) приложения:
HTTP метод CRUD действие ПОЛУЧИТЬ читать возвращает запрошенные данные ПОЧТА Создайте создает новую запись Положить или патч Обновить обновляет существующую запись УДАЛЯТЬ удалять удаляет существующую запись Примеры:
- запрос GET для
/user/
возвращает список зарегистрированных пользователей в системе - запрос POST к
/user/123
создает пользователя с идентификатором123
с использованием данных тела - запрос PUT для
/user/123
обновляет пользователя123
данными тела - запрос GET к
/user/123
возвращает данные пользователя123
- запрос DELETE к
/user/123
удаляет пользователя123
- запрос GET для
-
Заголовки HTTP . Такая информация, как токены аутентификации или файлы cookie, может содержаться в заголовке HTTP-запроса.
-
Данные тела . Обычно данные передаются в теле 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 может быть проверен, чтобы убедиться, что пользователь вошел в систему и имеет соответствующие права.
Сторонние приложения должны использовать альтернативные методы авторизации. Общие параметры аутентификации включают в себя:
- Базовая аутентификация HTTP . Заголовок HTTP-
Authorization
содержащий имя пользователя в кодировке base64: строка пароля передается в заголовке запроса. - API ключи . Стороннему приложению предоставляется разрешение на использование API путем выдачи ключа, который может иметь определенные права или быть ограниченным конкретным доменом. Ключ передается в каждом запросе в заголовке HTTP или в строке запроса.
- OAuth . Токен получается до того, как любой запрос может быть отправлен отправкой идентификатора клиента и, возможно, секрета клиента на сервер OAuth. Затем токен OAuth отправляется с каждым запросом API до истечения срока его действия.
- JSON Web Tokens (JWT) . Жетоны аутентификации с цифровой подписью надежно передаются как в заголовке запроса, так и в ответе.
Аутентификация API зависит от контекста использования. В некоторых случаях стороннее приложение считается другим зарегистрированным пользователем с определенными правами и разрешениями — например, при создании направлений из API карты. В других случаях стороннее приложение используется зарегистрированным пользователем и может получить доступ только к его данным — например, при получении содержимого или документов электронной почты.
Безопасность
RESTful API предоставляет другой путь для доступа к вашему приложению и управления им. Даже если это не интересная цель для взлома, клиент с плохим поведением может отправлять тысячи запросов каждую секунду и приводить к сбою вашего сервера.
Безопасность выходит за рамки данной статьи, но общие рекомендации включают в себя:
- использовать HTTPS
- использовать надежный метод аутентификации
- использовать CORS для ограничения вызовов на стороне клиента конкретными доменами
- обеспечить минимальную функциональность, то есть не создавать опции DELETE, которые не требуются
- проверить все URL конечной точки и данные тела
- избегать выставления токенов API в клиентском JavaScript
- заблокировать доступ с неизвестных доменов или IP-адресов
- блокировать неожиданно большие полезные нагрузки
- учитывайте ограничение скорости — то есть запросы, использующие один и тот же токен API или IP-адрес, ограничены N в минуту
- ответьте соответствующим кодом статуса HTTP и заголовком кэширования
- регистрировать запросы и расследовать сбои.
Несколько запросов и ненужных данных
API RESTful ограничены их реализацией. Ответ может содержать больше данных, чем вам нужно, или требовать дополнительных запросов для доступа ко всем данным.
Рассмотрим RESTful API, который предоставляет доступ к данным автора и книги. Чтобы показать данные для 10 самых продаваемых книг, клиент должен:
- Запросите первую 10
/book/
детали, упорядоченные по количеству продаж (сначала топ-продавец). Ответ содержит список книг с каждым идентификатором автора. - Выполните до 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 в ваших собственных проектах, прежде чем внедрять свои собственные веб-сервисы.