Это последняя статья из серии статей про REST API:
В этой статье вы познакомитесь с рекомендациями по REST API и с примерами разработки из Java и Spring Web Services.
При разработке хорошего REST API важно иметь хорошие микросервисы.
Как вы разрабатываете свой REST API? Каковы лучшие практики?
![](https://habrastorage.org/r/w1560/webt/2l/pg/rq/2lpgrq94xumpddkf6ivlt3ekkgu.png)
Кто будет пользоваться вашим сервисом? Потребитель услуг.
Вы смотрите на сервис с точки зрения потребителя?
Всякий раз, когда у вас проходит обсуждение или ревью сервиса, ставьте требования потребителя на первое место.
Что такое контракт?
Создатель веб-сервиса считается поставщиком сервиса. Приложение, которое использует веб-сервис, является потребителем сервиса. Контракт — это соглашение между поставщиком и потребителем об услуге.
![](https://habrastorage.org/r/w1560/webt/d-/5f/on/d-5fon8kmzaf6f_7g-bn7fsbofe.png)
Чтобы правильно использовать услугу, потребитель сервиса должен полностью понимать договор. Контракт включает в себя детали многих аспектов обслуживания, таких как:
Это также называется определением сервиса (service definition).
При contract first подходе вы сначала определяете контракт на обслуживание, а затем только внедряете сервис.
Например, когда вы определяете веб-службы SOAP, вы используете WSDL для определения договора.
![](https://habrastorage.org/r/w1560/webt/ou/st/86/oust86bvzc87vsg-k229x1ujl14.png)
WSDL определяет, каковы конечные точки службы, операции, которые вы публикуете, и структуры запроса и ответа.
Когда вы используете RESTful веб-сервисы, Swagger — это популярный инструмент для документирования ваших веб-сервисов.
![](https://habrastorage.org/r/w1560/webt/we/tc/3x/wetc3x4x6unbgve0wcaxdjdbkp8.png)
![](https://habrastorage.org/r/w1560/webt/l-/2m/h_/l-2mh_uh6txdtyekd1xn585mmvw.png)
Swagger позволяет вам определить, какие ресурсы вы предоставляете в рамках своего API. Он включает в себя детали каждой операции, например, использует ли он XML, JSON или оба. Схема ответов также присутствует там.
![](https://habrastorage.org/r/w1560/webt/9e/px/uh/9epxuhh57oelrv-dupcqib0t6ho.png)
Он также дает подробную информацию о кодах ответов, которые он поддерживает. Вы также можете увидеть, что этот конкретный ресурс, /jpa/users:
![](https://habrastorage.org/r/w1560/webt/gi/ig/pk/giigpknfhlsy8qiscbblp_eigdw.png)
поддерживает операцию GET. Фактически также поддерживает операцию POST:
![](https://habrastorage.org/r/w1560/webt/ox/9o/ch/ox9ochxtkao2ghxalyyi_o6oy4m.png)
Схема ответа, если этот ресурс доступен, будет:
![](https://habrastorage.org/r/w1560/webt/lf/gq/xo/lfgqxoi0txeqlqyg8vmblmppwdq.png)
Определение объекта User присутствует в договоре Swagger как:
![](https://habrastorage.org/r/w1560/webt/d3/s0/nm/d3s0nmktz3so7vqye4t8vqizwm4.png)
Он включает в себя атрибуты: birthDate, id, name и массив сообщений posts. Некоторые поля также включают в себя поле описания внутри них.
При contract first подходе перед внедрением сервиса вы вручную или с помощью приложения создаете такое определение, какое создал Swagger.
Используя contract first подход, вы думаете о своих потребителях и о том, как они могут использовать эту услугу. Вы изначально не беспокоитесь о деталях реализации.
Если на раннем этапе вы придаете большое значение внедрению, технические подробности проникают в определение вашего сервиса.
Вам нужно, чтобы определение вашего сервиса не зависело от используемой платформы, будь то Java, .NET или какая-либо еще.
Важным ориентиром для ваших организационных стандартов является YARAS.
![](https://habrastorage.org/r/w1560/webt/bu/9e/9s/bu9e9sa0bryvgm6g8yhhtabcdf0.png)
YARAS означает Yet Another RESTful API Standard (еще один стандарт RESTful API). YARAS предоставляет стандарты, руководства и соглашения, которые необходимо соблюдать при разработке RESTful веб-сервисов. Он дает рекомендации для следующих вещей:
Вам нужно решить множество сложных проблем, прежде чем приступить к проектированию RESTful веб-сервисов. Все перечисленное выше, необходимо выяснить.
Руководство вашей организация не захочет, чтобы команды, которые занимаются различными ресурсами, разные подходы к этим вещам.
Например, нежелательно, чтобы Команда-A организовывала версионность на основе параметров запроса, а Команда-B использовало версионность на основе URI.
Поэтому важно, чтобы у вас были четко определенные организационные стандарты для подхода к RESTful веб-сервисАМ.
Хорошая вещь в YARAS — это то, что он может быть настроен для удовлетворения потребностей, специфичных для организации. Например, вы можете:
Поскольку YARAS имеет достаточно всеобъемлющий охват, вы можете быть уверены, что не пропустили ни одного важного решения.
Типичными фреймвоками, которые используются для создания веб-сервисов RESTful в мире Java, являются Spring MVC, Spring REST и JAX-RS.
Если вы создадите специфичную для организации фреймвок/архетип/эталонное приложение, придерживающееся общих стандартов организации, поверх предпочтительной REST API платформы, это позволит командам легко придерживаться общих стандартов.
Типичные особенности включают в себя:
Стандартный фреймвок обеспечивает единый подход к проектированию и внедрению сервисов во всей организации.
Создайте группу экспертов из команд, создающих REST API, и сформируйте команду управления. Команда несет ответственность за
Всякий раз, когда вы думаете о веб-сервисах RESTful, думайте о HTTP.
HTTP имеет все функции, которые помогут вам создавать отличные веб-сервисы.
Подумайте о методах HTTP-запросов, которые вам нужно использовать. Когда вы думаете о реализации какой-либо операции, определите ресурс, на котором она должна быть выполнена, а затем найдите соответствующий метод HTTP-запроса. Вы извлекаете детали, создаете что-то, обновляете что-то существующее или удаляете существующее?
Использование HTTP методов:
При выполнении операции убедитесь, что вы вернули правильный статус ответа.
Например, когда конкретный ресурс не найден, не выбрасывайте исключение сервера. Вместо этого отправьте соответствующий код ответа в ответном сообщении, например 404.
Если на самом деле существует исключение сервера, отправьте обратно код 500.
В случае ошибки проверки отправьте код для неверного запроса.
Каждый ресурс может иметь несколько представлений — в формате XML или JSON. Потребитель услуг может выбрать представление по своему выбору.
Сервис возвращает 3 элемента users, когда мы отправляем запрос GET. В этом случае мы получаем JSON-представление ресурса /users.
![](https://habrastorage.org/r/w1560/webt/gq/qn/jq/gqqnjqeoz1e_lo1vftv0qymzdje.png)
Когда потребитель не указывает предпочтительное представление, мы используем JSON.
![](https://habrastorage.org/r/w1560/webt/ox/fr/b-/oxfrb-45qiilzqpul45nbdpqk6a.png)
Потребитель может отправить заголовок Accept, чтобы указать представление.
![](https://habrastorage.org/r/w1560/webt/df/tz/0t/dftz0teguhajcobfnjsgs-elmhk.png)
Тело ответа теперь имеет содержимое XML:
![](https://habrastorage.org/r/w1560/webt/bw/ct/io/bwctiow8vaxwy2sik1-awmyhar0.png)
Всегда используйте множественное число, когда вы именуете ресурсы.
Давайте посмотрим на простой пример. Предположим, у нас есть сервис, который размещает ресурс пользователя. Ниже описано, как получить к ним доступ:
Предпочтение множественного users единственному user делает URI более читабельным.
Потребители должны понимать, как наилучшим образом использовать сервис, и лучший способ помочь им — создавать хорошую документацию.
Веб-сервисы SOAP могут использовать функциональность WSDL, в то время как RESTful веб-сервисы имеют опции Swagger (теперь стандарт документации Open API).
Выбор формата — это только одна часть создания хорошей документации. Что также важно, так это предоставление нужного количества информации, чтобы помочь потребителю.
Документация должна быть полной и включать следующие пункты:
Полезно было бы иметь общий портал документации REST API для всей организации. Взгляните на один такой портал:
![](https://habrastorage.org/r/w1560/webt/3j/vm/bo/3jvmbovqx_sikaedwbkgzxe80yc.png)
Такой портал объединяет все ресурсы, имеющиеся в организации. Наличие пользовательского интерфейса, такого как Swagger UI, будет иметь свои дополнительные преимущества. Используя Swagger UI, вы можете посмотреть документацию более подробно:
![](https://habrastorage.org/r/w1560/webt/xp/io/ox/xpiooxhstlexwhwjxqk9umd6yye.png)
Это может быть использовано даже нетехническими пользователями. Информация, предоставляемая здесь, включает в себя:
Интерес также может представлять формат документации в стиле «живой запрос/ответ».
Управление версиями влечет за собой большую сложность для веб-службы. Поддерживать несколько разных версий одного и того же веб-сервиса очень сложно. Старайтесь избегать этого, когда это возможно.
Однако в определенных сценариях управление версиями неизбежно.
Давайте начнем с рассмотрения примера службы. Предположим, что мы изначально определили службу, имеющую класс PersonV1, следующим образом:
Эта версия класса не учитывает, что у имени может быть много подразделов, таких как имя и фамилия. Посмотрите это:
Вторая версия исходного класса была обновлена, чтобы исправить эту аномалию:
Мы не можем сразу перенести весь сервис для использования PersonV2! Там могут быть другие потребители, которые ожидают ответов в формате PersonV1.
Вот где требуется управление версиями.
Давайте теперь посмотрим на варианты, которые мы имеем для управления версиями этих двух ресурсов.
У нас есть один вариант — использовать разные URI для этих разных ресурсов. В приведенном ниже коде экзамена мы используем URI v1/person и v2/person для их различения:
Если вы выполняете запрос GET для ресурса v1/person:
![](https://habrastorage.org/r/w1560/webt/ro/xv/go/roxvgoo6pek2xv4wokws2zivir4.png)
Вы получите информацию, соответствующую v1. Для другого ресурса:
![](https://habrastorage.org/r/w1560/webt/hn/yn/vh/hnynvhniet9iacsxsrikaa9pxj8.png)
Второй метод управления версиями использует параметр запроса:
В URI /person/param, если мы отправляем параметр с версией=1, мы возвращаем ресурс типа PersonV1:
![](https://habrastorage.org/r/w1560/webt/sp/qe/1g/spqe1gs9bksyba0pmidzsndo1fm.png)
Для того же URI параметр с version=2 возвращает ресурс типа PersonV2:
![](https://habrastorage.org/r/w1560/webt/2q/qt/q1/2qqtq1ci6j_pg4bc6brglrj4z88.png)
Этот метод называется управлением версиями с помощью параметров запроса.
Другим способом вы можете сделать это управление версиями, указав заголовок. Здесь мы используем заголовок с именем X-API-VERSION и пометили URI как /person/header. Когда значение заголовка равно 1, возвращается ресурс типа PersonV1:
![](https://habrastorage.org/r/w1560/webt/d-/0b/ww/d-0bwwbim3yedwkmreql8hancrg.png)
Когда его значение равно 2, ресурс типа PersonV2 извлекается:
![](https://habrastorage.org/r/w1560/webt/yz/_q/1-/yz_q1-fcemb3sqptsk4cd5p8kno.png)
Мы используем атрибут в заголовке запроса, чтобы выполнить управление версиями для нас.
Последний метод для создания версий использует Accept Header. Если потребитель включает первую информацию о версиях в Accept Header запроса GET, возвращается следующий ресурс:
![](https://habrastorage.org/r/w1560/webt/dz/yw/54/dzyw5423iw2i6ogaiund7wpl1wo.png)
В противном случае возвращается ресурс типа PersonV2:
![](https://habrastorage.org/r/w1560/webt/3i/a4/wl/3ia4wlgl4dbx9fvpxvz3ho8ihxc.png)
Этот способ управления версией называется Accept Header Versioning или Media Type Versioning, поскольку MIME-типы обычно являются содержимым заголовка Accept.
До сих пор мы видели четыре типа методов версиями:
Какой из них самый лучший? Правда в том, что на этот вопрос нет однозначного ответа. В том-то и дело, что разные интернет-гиганты покровительствуют разным типам версий.
Вам необходимо оценить эти четыре варианта в соответствии с вашими конкретными потребностями. Есть ряд важных факторов, которые следует учитывать:
Поймите, что не существует единого идеального решения!
Когда потребитель отправляет запрос в службу, важно, чтобы он получил правильный ответ. Всякий раз, когда что-то идет не так, важно отправить соответствующий ответ.
Если мы отправим запрос GET для поиска существующего пользователя, мы получим следующий ответ:
![](https://habrastorage.org/r/w1560/webt/uv/dl/9j/uvdl9jri5sd_xafc-fog6acw0rm.png)
Если вы ищете несуществующего пользователя:
![](https://habrastorage.org/r/w1560/webt/9z/kq/je/9zkqjeitglkibqhxszf-4_qr9xk.png)
То, что вы получите, это статус 404 Not Found. Это хорошая обработка ошибок, поскольку она правильно определяет, что ресурс не найден, и не возвращает ошибку сервера.
Давайте теперь отправим запрос GET на несуществующий URI:
![](https://habrastorage.org/r/w1560/webt/gp/b9/ch/gpb9ch3b9ochiotgxppztr4zyb4.png)
Как видидите, вы получаете статусы ответа 404 Not Found. Неправильный URL указывает на несуществующий ресурс.
Это помогает, если у вас есть стандартная структура исключений при разработке вашего сервиса.
![](https://habrastorage.org/r/w1560/webt/fd/ds/vd/fddsvdk0uirskh9ubp4oprwdcd8.png)
Для конкретных ошибок конкретные структуры ответа могут быть возвращены потребителю, и это может быть стандартом во всей организации. Убедитесь, что ответ об ошибке также читается потребителям, без путаницы.
Swagger обеспечивает один из самых популярных форматов документации для веб-сервисов RESTful. Сегодня он поддерживается различными организациями и используется в большом количестве услуг. Здесь мы рассмотрим два основных аспекта Swagger:
Посмотрите на следующий Swagger JSON:
![](https://habrastorage.org/r/w1560/webt/76/da/mo/76damom8ezs7j-5amuzvwfxrh6q.png)
На верхнем уровне это выглядит очень похоже на определение WSDL. У него есть несколько важных атрибутов:
![](https://habrastorage.org/r/w1560/webt/em/iz/q0/emizq09g1kavjozxl2-dnasjuum.png)
![](https://habrastorage.org/r/w1560/webt/eu/5w/wg/eu5wwgbarvmsawqrqslbu3ps9oa.png)
![](https://habrastorage.org/r/w1560/webt/j0/y7/9d/j0y79dcqh83k2kak44d7te-fb3q.png)
Когда вы посмотрите на документацию по Swagger, вы сможете быстро определить имеющиеся ресурсы, поддерживаемые операции и операции, относящиеся к каждому ресурсу:
![](https://habrastorage.org/r/w1560/webt/bx/dx/5c/bxdx5cazvuaggiwdhkqrxcwp1es.png)
Ресурс /users поддерживает операции GET и POST. Для GET вы можете увидеть поддерживаемые типы запросов и ответов. Вы также видите различные типы ответов:
![](https://habrastorage.org/r/w1560/webt/_1/gk/p6/_1gkp6wgcm4_lql3lnlrt49okvg.png)
Обратите внимание, что для ответа 200 схема также упоминается как массив User. User является частью раздела definitions (определения) в нижней части документа:
![](https://habrastorage.org/r/w1560/webt/wa/-4/9o/wa-49o7ao-f8_lpf-ifh4zptvks.png)
Swagger полностью независим от технологии, которую вы используете для реализации RESTful веб-сервиса. О все работает на основе JSON.
Swagger UI — отличный пользовательский интерфейс, который очень полезен для визуализации документации Swagger для веб-службы RESTful. Посмотрите на скриншот ниже:
![](https://habrastorage.org/r/w1560/webt/8_/up/yn/8_upynbqoldixni50vm45okd39c.png)
Обратите внимание, что мы выбрали конкретную версию веб-сервиса для просмотра его документации. Вот тот же экран более подробно:
![](https://habrastorage.org/r/w1560/webt/ex/qu/4i/exqu4ioa6t5fai0zagud42n8w_k.png)
Когда мы заходим на домашнюю страницу, она описывает перечисленные ресурсы:
![](https://habrastorage.org/r/w1560/webt/or/df/3-/ordf3-wrutjlzbey_oxfudbydcm.png)
Также можно увидеть набор операций, поддерживаемых для URL ресурсов:
![](https://habrastorage.org/r/w1560/webt/3z/8m/6q/3z8m6qrd6sgoyteluxobp7duiim.png)
Когда вы нажимаете на операцию GET определенного ресурса, вы получаете его детали:
![](https://habrastorage.org/r/w1560/webt/sw/rg/ps/swrgpsafvap9hwycxgqkphfkds0.png)
Вы можете увидеть, что схема модели описана визуально. Атрибуты birthDate, id, links, name и posts также отображаются. Вы также можете выполнить пример запроса и просмотреть ответ:
![](https://habrastorage.org/r/w1560/webt/xb/np/ec/xbnpec9iiud7vdkdqok6scnu-uc.png)
Самое замечательное в Swagger — множество инструментов, доступных вокруг него. Взгляните на следующий сервис, который мы использовали ранее, чтобы объяснить управление версиями: Вот посмотрите на автоматически сгенерированную документацию для этого сервиса:
![](https://habrastorage.org/r/w1560/webt/vi/el/hn/vielhn-jq9zvj5ql30hgnu0kzme.png)
В Swagger есть поддержка как подхода contract-first, так и подхода code-first.
По этому вопросу имеется авторское видео.
В этой статье мы рассмотрели лучшие практики создания и проектирования RESTful веб-сервисов.
Be the BEST at Your REST API!
Developing REST APIs
- Введение в REST API — RESTful веб-сервисы
- Различия REST и SOAP
- Разработка REST API — что такое Contract First (контракт в первую очередь)?
- Разработка REST API — что такое Code First (код в первую очередь)?
- REST API — Что такое HATEOAS?
- Рекомендации по REST API — примеры проектирования веб-сервисов на Java и Spring
В этой статье вы познакомитесь с рекомендациями по REST API и с примерами разработки из Java и Spring Web Services.
При разработке хорошего REST API важно иметь хорошие микросервисы.
Как вы разрабатываете свой REST API? Каковы лучшие практики?
![](https://habrastorage.org/webt/2l/pg/rq/2lpgrq94xumpddkf6ivlt3ekkgu.png)
Вы изучите:
- Как разрабатывать хороший REST API?
- О чем следует думать при разработке REST API?
- Каковы лучшие практики при разработке RESTful веб-сервисов?
Используйте Consumer First подход
Кто будет пользоваться вашим сервисом? Потребитель услуг.
Вы смотрите на сервис с точки зрения потребителя?
- Если вы разрабатываете API, сможет ли ваш потребитель понять ваш API?
- Если вы опубликуете свои ресурсы, сможет ли потребитель найти и получить к ним доступ?
- Сможет ли потребитель понять ваши URI?
- Какой тип услуги вы предоставляете?
- Это мобильное приложение или веб-приложение?
- Каких потребителей вы ожидаете, и могут ли эти типы потребителей измениться в будущем?
- Если вы реализуете что-то вроде HATEOAS, подумайте, как ваши потребители будут использовать это, прежде чем внедрять.
- Самое главное — иметь отличную документацию
- Сделайте вещи проще для ваших потребителей, чтобы сэкономить ваше время
- Чем больше потребители могут сделать самостоятельно, тем меньше работы для вас
Всякий раз, когда у вас проходит обсуждение или ревью сервиса, ставьте требования потребителя на первое место.
Используйте Contract First подход
Что такое контракт?
Создатель веб-сервиса считается поставщиком сервиса. Приложение, которое использует веб-сервис, является потребителем сервиса. Контракт — это соглашение между поставщиком и потребителем об услуге.
![](https://habrastorage.org/webt/d-/5f/on/d-5fon8kmzaf6f_7g-bn7fsbofe.png)
Чтобы правильно использовать услугу, потребитель сервиса должен полностью понимать договор. Контракт включает в себя детали многих аспектов обслуживания, таких как:
- Как вызвать веб-сервис?
- Какой транспорт используется?
- Каковы структуры запроса и ответа?
Это также называется определением сервиса (service definition).
При contract first подходе вы сначала определяете контракт на обслуживание, а затем только внедряете сервис.
Contract First с WSDL
Например, когда вы определяете веб-службы SOAP, вы используете WSDL для определения договора.
![](https://habrastorage.org/webt/ou/st/86/oust86bvzc87vsg-k229x1ujl14.png)
WSDL определяет, каковы конечные точки службы, операции, которые вы публикуете, и структуры запроса и ответа.
Contract First с Swagger / Open API
Когда вы используете RESTful веб-сервисы, Swagger — это популярный инструмент для документирования ваших веб-сервисов.
![](https://habrastorage.org/webt/we/tc/3x/wetc3x4x6unbgve0wcaxdjdbkp8.png)
![](https://habrastorage.org/webt/l-/2m/h_/l-2mh_uh6txdtyekd1xn585mmvw.png)
Swagger позволяет вам определить, какие ресурсы вы предоставляете в рамках своего API. Он включает в себя детали каждой операции, например, использует ли он XML, JSON или оба. Схема ответов также присутствует там.
![](https://habrastorage.org/webt/9e/px/uh/9epxuhh57oelrv-dupcqib0t6ho.png)
Он также дает подробную информацию о кодах ответов, которые он поддерживает. Вы также можете увидеть, что этот конкретный ресурс, /jpa/users:
![](https://habrastorage.org/webt/gi/ig/pk/giigpknfhlsy8qiscbblp_eigdw.png)
поддерживает операцию GET. Фактически также поддерживает операцию POST:
![](https://habrastorage.org/webt/ox/9o/ch/ox9ochxtkao2ghxalyyi_o6oy4m.png)
Схема ответа, если этот ресурс доступен, будет:
![](https://habrastorage.org/webt/lf/gq/xo/lfgqxoi0txeqlqyg8vmblmppwdq.png)
Определение объекта User присутствует в договоре Swagger как:
![](https://habrastorage.org/webt/d3/s0/nm/d3s0nmktz3so7vqye4t8vqizwm4.png)
Он включает в себя атрибуты: birthDate, id, name и массив сообщений posts. Некоторые поля также включают в себя поле описания внутри них.
При contract first подходе перед внедрением сервиса вы вручную или с помощью приложения создаете такое определение, какое создал Swagger.
Преимущества подхода Contract First
Используя contract first подход, вы думаете о своих потребителях и о том, как они могут использовать эту услугу. Вы изначально не беспокоитесь о деталях реализации.
Если на раннем этапе вы придаете большое значение внедрению, технические подробности проникают в определение вашего сервиса.
Вам нужно, чтобы определение вашего сервиса не зависело от используемой платформы, будь то Java, .NET или какая-либо еще.
Определите организационные стандарты для REST API
Важным ориентиром для ваших организационных стандартов является YARAS.
![](https://habrastorage.org/webt/bu/9e/9s/bu9e9sa0bryvgm6g8yhhtabcdf0.png)
YARAS означает Yet Another RESTful API Standard (еще один стандарт RESTful API). YARAS предоставляет стандарты, руководства и соглашения, которые необходимо соблюдать при разработке RESTful веб-сервисов. Он дает рекомендации для следующих вещей:
- Как вы должны назвать свои услуги
- Как вы должны структурировать свой запрос и ответ
- Как вы должны реализовать фильтрацию, сортировку, разбиение на страницы и другие действия
- Как вы должны подходить к версионированию
- Как вам нужно подходить к документации API
Единый подход к разработке сервисов
Вам нужно решить множество сложных проблем, прежде чем приступить к проектированию RESTful веб-сервисов. Все перечисленное выше, необходимо выяснить.
Руководство вашей организация не захочет, чтобы команды, которые занимаются различными ресурсами, разные подходы к этим вещам.
Например, нежелательно, чтобы Команда-A организовывала версионность на основе параметров запроса, а Команда-B использовало версионность на основе URI.
Поэтому важно, чтобы у вас были четко определенные организационные стандарты для подхода к RESTful веб-сервисАМ.
Кастомизация YARAS ПОД организационные нужды
Хорошая вещь в YARAS — это то, что он может быть настроен для удовлетворения потребностей, специфичных для организации. Например, вы можете:
- Настройте, как должны выглядеть тела запросов и ответов
- Выберите конкретный вид системы управления версиями
Поскольку YARAS имеет достаточно всеобъемлющий охват, вы можете быть уверены, что не пропустили ни одного важного решения.
Выбор стандартного общеорганизационного REST API фреймвока
Типичными фреймвоками, которые используются для создания веб-сервисов RESTful в мире Java, являются Spring MVC, Spring REST и JAX-RS.
Если вы создадите специфичную для организации фреймвок/архетип/эталонное приложение, придерживающееся общих стандартов организации, поверх предпочтительной REST API платформы, это позволит командам легко придерживаться общих стандартов.
Типичные особенности включают в себя:
- Структуры запросов и ответов
- Обработка ошибок
- фильтрация
- Поиск
- Versioning
- Поддержка ложных ответов
- HATEOAS
Стандартный фреймвок обеспечивает единый подход к проектированию и внедрению сервисов во всей организации.
Децентрализованное управление REST API
Создайте группу экспертов из команд, создающих REST API, и сформируйте команду управления. Команда несет ответственность за
- Улучшение стандартов REST API
- Построение / Проектирование ваших REST API фреймвоков
Широкое использование HTTP
Всякий раз, когда вы думаете о веб-сервисах RESTful, думайте о HTTP.
HTTP имеет все функции, которые помогут вам создавать отличные веб-сервисы.
Используйте правильные методы HTTP-запросов
Подумайте о методах HTTP-запросов, которые вам нужно использовать. Когда вы думаете о реализации какой-либо операции, определите ресурс, на котором она должна быть выполнена, а затем найдите соответствующий метод HTTP-запроса. Вы извлекаете детали, создаете что-то, обновляете что-то существующее или удаляете существующее?
Использование HTTP методов:
- GET для получения
- POST для создания
- PUT для обновления
- DELETE для удаления
- PATCH для частичных обновлений
Используйте соответствующий статус ответа HTTP
При выполнении операции убедитесь, что вы вернули правильный статус ответа.
Например, когда конкретный ресурс не найден, не выбрасывайте исключение сервера. Вместо этого отправьте соответствующий код ответа в ответном сообщении, например 404.
Если на самом деле существует исключение сервера, отправьте обратно код 500.
В случае ошибки проверки отправьте код для неверного запроса.
Фокус на представление
Каждый ресурс может иметь несколько представлений — в формате XML или JSON. Потребитель услуг может выбрать представление по своему выбору.
Сервис возвращает 3 элемента users, когда мы отправляем запрос GET. В этом случае мы получаем JSON-представление ресурса /users.
![](https://habrastorage.org/webt/gq/qn/jq/gqqnjqeoz1e_lo1vftv0qymzdje.png)
Когда потребитель не указывает предпочтительное представление, мы используем JSON.
![](https://habrastorage.org/webt/ox/fr/b-/oxfrb-45qiilzqpul45nbdpqk6a.png)
Потребитель может отправить заголовок Accept, чтобы указать представление.
![](https://habrastorage.org/webt/df/tz/0t/dftz0teguhajcobfnjsgs-elmhk.png)
Тело ответа теперь имеет содержимое XML:
![](https://habrastorage.org/webt/bw/ct/io/bwctiow8vaxwy2sik1-awmyhar0.png)
Используйте множественное число
Всегда используйте множественное число, когда вы именуете ресурсы.
Давайте посмотрим на простой пример. Предположим, у нас есть сервис, который размещает ресурс пользователя. Ниже описано, как получить к ним доступ:
- Создать пользователя: POST /users
- Удалить пользователя: DELETE /users/1
- Получить всех пользователей: GET /users
- Получить одного пользователя: GET /users/1
Предпочтение множественного users единственному user делает URI более читабельным.
- Например, если мы используем /user вместо /users для получения, GET /user не передает правильное сообщение читателю.
Создать хорошую документацию
Потребители должны понимать, как наилучшим образом использовать сервис, и лучший способ помочь им — создавать хорошую документацию.
Веб-сервисы SOAP могут использовать функциональность WSDL, в то время как RESTful веб-сервисы имеют опции Swagger (теперь стандарт документации Open API).
Выбор формата — это только одна часть создания хорошей документации. Что также важно, так это предоставление нужного количества информации, чтобы помочь потребителю.
Документация должна быть полной и включать следующие пункты:
- Что такое структура запроса и ответа?
- Как потребитель должен аутентифицировать себя?
- Каковы пределы использования?
- Укажите все типы ответных сообщений и соответствующие коды состояния, которые можно ожидать от службы
Создать общий портал документации REST API
Полезно было бы иметь общий портал документации REST API для всей организации. Взгляните на один такой портал:
![](https://habrastorage.org/webt/3j/vm/bo/3jvmbovqx_sikaedwbkgzxe80yc.png)
Такой портал объединяет все ресурсы, имеющиеся в организации. Наличие пользовательского интерфейса, такого как Swagger UI, будет иметь свои дополнительные преимущества. Используя Swagger UI, вы можете посмотреть документацию более подробно:
![](https://habrastorage.org/webt/xp/io/ox/xpiooxhstlexwhwjxqk9umd6yye.png)
Это может быть использовано даже нетехническими пользователями. Информация, предоставляемая здесь, включает в себя:
- Ожидаемый формат ответа
- Тип контента
- Поддерживаемые коды ответов
Интерес также может представлять формат документации в стиле «живой запрос/ответ».
Поддержка версий
Управление версиями влечет за собой большую сложность для веб-службы. Поддерживать несколько разных версий одного и того же веб-сервиса очень сложно. Старайтесь избегать этого, когда это возможно.
Однако в определенных сценариях управление версиями неизбежно.
Давайте начнем с рассмотрения примера службы. Предположим, что мы изначально определили службу, имеющую класс PersonV1, следующим образом:
Эта версия класса не учитывает, что у имени может быть много подразделов, таких как имя и фамилия. Посмотрите это:
Вторая версия исходного класса была обновлена, чтобы исправить эту аномалию:
Мы не можем сразу перенести весь сервис для использования PersonV2! Там могут быть другие потребители, которые ожидают ответов в формате PersonV1.
Вот где требуется управление версиями.
Давайте теперь посмотрим на варианты, которые мы имеем для управления версиями этих двух ресурсов.
Использование разных URI
У нас есть один вариант — использовать разные URI для этих разных ресурсов. В приведенном ниже коде экзамена мы используем URI v1/person и v2/person для их различения:
Если вы выполняете запрос GET для ресурса v1/person:
![](https://habrastorage.org/webt/ro/xv/go/roxvgoo6pek2xv4wokws2zivir4.png)
Вы получите информацию, соответствующую v1. Для другого ресурса:
![](https://habrastorage.org/webt/hn/yn/vh/hnynvhniet9iacsxsrikaa9pxj8.png)
Использование параметра запроса
Второй метод управления версиями использует параметр запроса:
В URI /person/param, если мы отправляем параметр с версией=1, мы возвращаем ресурс типа PersonV1:
![](https://habrastorage.org/webt/sp/qe/1g/spqe1gs9bksyba0pmidzsndo1fm.png)
Для того же URI параметр с version=2 возвращает ресурс типа PersonV2:
![](https://habrastorage.org/webt/2q/qt/q1/2qqtq1ci6j_pg4bc6brglrj4z88.png)
Этот метод называется управлением версиями с помощью параметров запроса.
Использование Header (заголовка)
Другим способом вы можете сделать это управление версиями, указав заголовок. Здесь мы используем заголовок с именем X-API-VERSION и пометили URI как /person/header. Когда значение заголовка равно 1, возвращается ресурс типа PersonV1:
![](https://habrastorage.org/webt/d-/0b/ww/d-0bwwbim3yedwkmreql8hancrg.png)
Когда его значение равно 2, ресурс типа PersonV2 извлекается:
![](https://habrastorage.org/webt/yz/_q/1-/yz_q1-fcemb3sqptsk4cd5p8kno.png)
Мы используем атрибут в заголовке запроса, чтобы выполнить управление версиями для нас.
Использование Accept Header
Последний метод для создания версий использует Accept Header. Если потребитель включает первую информацию о версиях в Accept Header запроса GET, возвращается следующий ресурс:
![](https://habrastorage.org/webt/dz/yw/54/dzyw5423iw2i6ogaiund7wpl1wo.png)
В противном случае возвращается ресурс типа PersonV2:
![](https://habrastorage.org/webt/3i/a4/wl/3ia4wlgl4dbx9fvpxvz3ho8ihxc.png)
Этот способ управления версией называется Accept Header Versioning или Media Type Versioning, поскольку MIME-типы обычно являются содержимым заголовка Accept.
Сравнение методов управления версиями
До сих пор мы видели четыре типа методов версиями:
- Использование разных URI
- Использование параметра запроса
- Использование заголовка
- Использование Accept Header / Media Type
Какой из них самый лучший? Правда в том, что на этот вопрос нет однозначного ответа. В том-то и дело, что разные интернет-гиганты покровительствуют разным типам версий.
- Использование разных URI — Twitter
- Использование параметра запроса — Amazon
- Использование заголовка — Microsoft
- Использование Accept Header / Media Type — GitHub
Вам необходимо оценить эти четыре варианта в соответствии с вашими конкретными потребностями. Есть ряд важных факторов, которые следует учитывать:
- URI Pollution (Загрязнение URI): управляя версиями с использованием URI и параметров запроса мы в конечном итоге загрязняем пространство URI. Это происходит потому, что мы добавляем префиксы и суффиксы к основным строкам URI. Управление версиями с использованием заголовка позволяет избежать этого.
- Misuse Of HTTP Headers (Неправильное использование заголовков HTTP). В случае управления версиями с использованием заголовков и Media Type происходит неправильное использование заголовков HTTP, поскольку они изначально не предназначались для управления версиями.
- Caching (Кэширование): ресурс определяется его URI. Однако, если вы не используете URI для определения его версии, а используете механизм на основе заголовка, информация о версиях не может быть кэширована. Если для вас важно HTTP-кеширование, используйте управления версиями на основе URI или параметра запроса.
- Browser Request Executability (Выполняемость запроса браузера): для управления версиями на основе заголовка и типа медиа требуется использование таких инструментов, как Postman. Тем не менее, если потребители службы не разбираются в технических вопросах, то предпочтительнее использовать управления версиями на основе URI или параметра запроса.
- API Documentation (Документация API): Вам также нужно подумать о том, как вы хотите документировать свои API. Версионность на основе URI и параметра запроса проще документировать, чем два других типа управления версиями.
Поймите, что не существует единого идеального решения!
Подумайте об обработке ошибок
Когда потребитель отправляет запрос в службу, важно, чтобы он получил правильный ответ. Всякий раз, когда что-то идет не так, важно отправить соответствующий ответ.
Когда потребитель запрашивает несуществующий ресурс
Если мы отправим запрос GET для поиска существующего пользователя, мы получим следующий ответ:
![](https://habrastorage.org/webt/uv/dl/9j/uvdl9jri5sd_xafc-fog6acw0rm.png)
Если вы ищете несуществующего пользователя:
![](https://habrastorage.org/webt/9z/kq/je/9zkqjeitglkibqhxszf-4_qr9xk.png)
То, что вы получите, это статус 404 Not Found. Это хорошая обработка ошибок, поскольку она правильно определяет, что ресурс не найден, и не возвращает ошибку сервера.
Давайте теперь отправим запрос GET на несуществующий URI:
![](https://habrastorage.org/webt/gp/b9/ch/gpb9ch3b9ochiotgxppztr4zyb4.png)
Как видидите, вы получаете статусы ответа 404 Not Found. Неправильный URL указывает на несуществующий ресурс.
Важные статусы ответа
- 200 — успех
- 404 — ресурс не найден
- 400 — неверный запрос (например, ошибка проверки)
- 201 — создан
- 401 — несанкционированный (при неудачной авторизации)
- 500 — ошибка сервера
Сведения об ошибках в теле ответа
Это помогает, если у вас есть стандартная структура исключений при разработке вашего сервиса.
![](https://habrastorage.org/webt/fd/ds/vd/fddsvdk0uirskh9ubp4oprwdcd8.png)
Для конкретных ошибок конкретные структуры ответа могут быть возвращены потребителю, и это может быть стандартом во всей организации. Убедитесь, что ответ об ошибке также читается потребителям, без путаницы.
Использование Swagger или Open API Documentation
Swagger обеспечивает один из самых популярных форматов документации для веб-сервисов RESTful. Сегодня он поддерживается различными организациями и используется в большом количестве услуг. Здесь мы рассмотрим два основных аспекта Swagger:
- Формат документации Swagger
- Swagger UI, который позволяет вам смотреть на документацию Swagger визуально удобным способом
Swagger Документация
Посмотрите на следующий Swagger JSON:
![](https://habrastorage.org/webt/76/da/mo/76damom8ezs7j-5amuzvwfxrh6q.png)
На верхнем уровне это выглядит очень похоже на определение WSDL. У него есть несколько важных атрибутов:
- host: где размещен сервис
- basePath: путь, где размещен сервис
- consumes: какие запросы принимаются
![](https://habrastorage.org/webt/em/iz/q0/emizq09g1kavjozxl2-dnasjuum.png)
- produces: Какие виды ответов генерируются
![](https://habrastorage.org/webt/eu/5w/wg/eu5wwgbarvmsawqrqslbu3ps9oa.png)
- paths: различные имеющиеся ресурсы В этом случае у вас есть несколько типов ресурсов в списке:
![](https://habrastorage.org/webt/j0/y7/9d/j0y79dcqh83k2kak44d7te-fb3q.png)
Когда вы посмотрите на документацию по Swagger, вы сможете быстро определить имеющиеся ресурсы, поддерживаемые операции и операции, относящиеся к каждому ресурсу:
![](https://habrastorage.org/webt/bx/dx/5c/bxdx5cazvuaggiwdhkqrxcwp1es.png)
Ресурс /users поддерживает операции GET и POST. Для GET вы можете увидеть поддерживаемые типы запросов и ответов. Вы также видите различные типы ответов:
![](https://habrastorage.org/webt/_1/gk/p6/_1gkp6wgcm4_lql3lnlrt49okvg.png)
Обратите внимание, что для ответа 200 схема также упоминается как массив User. User является частью раздела definitions (определения) в нижней части документа:
![](https://habrastorage.org/webt/wa/-4/9o/wa-49o7ao-f8_lpf-ifh4zptvks.png)
Swagger полностью независим от технологии, которую вы используете для реализации RESTful веб-сервиса. О все работает на основе JSON.
Представляем Swagger UI
Swagger UI — отличный пользовательский интерфейс, который очень полезен для визуализации документации Swagger для веб-службы RESTful. Посмотрите на скриншот ниже:
![](https://habrastorage.org/webt/8_/up/yn/8_upynbqoldixni50vm45okd39c.png)
Обратите внимание, что мы выбрали конкретную версию веб-сервиса для просмотра его документации. Вот тот же экран более подробно:
![](https://habrastorage.org/webt/ex/qu/4i/exqu4ioa6t5fai0zagud42n8w_k.png)
Когда мы заходим на домашнюю страницу, она описывает перечисленные ресурсы:
![](https://habrastorage.org/webt/or/df/3-/ordf3-wrutjlzbey_oxfudbydcm.png)
Также можно увидеть набор операций, поддерживаемых для URL ресурсов:
![](https://habrastorage.org/webt/3z/8m/6q/3z8m6qrd6sgoyteluxobp7duiim.png)
Когда вы нажимаете на операцию GET определенного ресурса, вы получаете его детали:
![](https://habrastorage.org/webt/sw/rg/ps/swrgpsafvap9hwycxgqkphfkds0.png)
Вы можете увидеть, что схема модели описана визуально. Атрибуты birthDate, id, links, name и posts также отображаются. Вы также можете выполнить пример запроса и просмотреть ответ:
![](https://habrastorage.org/webt/xb/np/ec/xbnpec9iiud7vdkdqok6scnu-uc.png)
Использование инструментов Swagger (стандарт Open API)
Самое замечательное в Swagger — множество инструментов, доступных вокруг него. Взгляните на следующий сервис, который мы использовали ранее, чтобы объяснить управление версиями: Вот посмотрите на автоматически сгенерированную документацию для этого сервиса:
![](https://habrastorage.org/webt/vi/el/hn/vielhn-jq9zvj5ql30hgnu0kzme.png)
В Swagger есть поддержка как подхода contract-first, так и подхода code-first.
По этому вопросу имеется авторское видео.
Резюме
В этой статье мы рассмотрели лучшие практики создания и проектирования RESTful веб-сервисов.
Дополнительное чтение
Be the BEST at Your REST API!
Developing REST APIs