RESTful API может создаваться не только для сторонних сервисов. Он может использоваться одностраничными приложениями для работы с бэк-эндом. Вот несколько основных моментов, которые нужно знать при проектировании интерфейса.
Ключевым принципом REST является деление вашего API на логические ресурсы. Управление этими ресурсами происходит с помощью HTTP-запросов с соответствующим методом — GET, POST, PUT, PATCH, DELETE.
Ресурс должен описываться существительным во множественном числе. Действия над ресурсами, обычно, определяются стратегией CRUD и соответствуют HTTP-методам следующим образом:
Если ресурс существует только в контексте другого ресурса, то URL может быть составным:
Когда действие над объектом не соответствует CRUD операции, то его можно рассматривать как составной ресурс:
Методы POST, PUT или PATCH могут изменять поля ресурса, которые не были включены в запрос (например, ID, дата создания или дата обновления). Чтобы не вынуждать пользователя API выполнять ещё один запрос на получение обновлённых данных, такие методы должны вернуть их в ответе.
Любые параметры в HTTP-запросе могут быть использованы для уточнения запроса или сортировки данных.
Когда нужно в ответ на запрос списка объектов добавить информацию о постраничной навигации, стоит воспользоваться HTTP-заголовком Link, а не добавлять обёртки данным.
Важно следовать этим значениям, а не конструировать собственные URL-ы потому, что иногда постраничная навигация может основываться на сложных правилах, а не простом переборе страниц.
Для совместимости с некоторыми серверами или клиентами, которые не поддерживают другие HTTP-методы кроме GET и POST, может быть полезным их эмуляция. Значение метода передаётся в заголовке X-HTTP-Method-Override
, а сам он выполняется как POST-метод. GET-запросы не должны менять состояние сервера!
В случае ошибок, в ответе может содержаться отладочная информация для разработчиков, если это возможно.
Любые данные, которые лишь опосредованно относятся к результату запроса, но могут быть полезны клиенту, стоит отдавать в виде HTTP-заголовков. Создание обёрток над данными ломает совместимость с принципами REST.
noteskeeper.ru
HTTP GET
Use GET requests to retrieve resource representation/information only – and not to modify it in any way. As GET requests do not change the state of the resource, these are said to be safe methods . Additionally, GET APIs should be idempotent , which means that making multiple identical requests must produce the same result every time until another API (POST or PUT) has changed the state of the resource on the server.
If the Request-URI refers to a data-producing process, it is the produced data which shall be returned as the entity in the response and not the source text of the process, unless that text happens to be the output of the process.
For any given HTTP GET API, if the resource is found on the server then it must return HTTP response code 200 (OK)
– along with response body which is usually either XML or JSON content (due to their platform independent nature).
In case resource is NOT found on server then it must return HTTP response code 404 (NOT FOUND)
. Similarly, if it is determined that GET request itself is not correctly formed then server will return HTTP response code 400 (BAD REQUEST)
.
Example request URIs
HTTP GET http://www.appdomain.com/users
HTTP GET http://www.appdomain.com/users?size=20&page=5
HTTP GET http://www.appdomain.com/users/123
HTTP GET http://www.appdomain.com/users/123/address
HTTP POST
Use POST APIs to create new subordinate resources , e.g. a file is subordinate to a directory containing it or a row is subordinate to a database table. Talking strictly in terms of REST, POST methods are used to create a new resource into the collection of resources.
Ideally, if a resource has been created on the origin server, the response SHOULD be HTTP response code 201 (Created)
and contain an entity which describes the status of the request and refers to the new resource, and a Location header.
Many times, the action performed by the POST method might not result in a resource that can be identified by a URI. In this case, either HTTP response code 200 (OK)
or 204 (No Content)
is the appropriate response status.
Responses to this method are not cacheable , unless the response includes appropriate Cache-Control or Expires header fields.
Please note that POST is neither safe nor idempotent and invoking two identical POST requests will result in two different resources containing the same information (except resource ids).
Example request URIs
HTTP POST http://www.appdomain.com/users
HTTP POST http://www.appdomain.com/users/123/accounts
HTTP PUT
Use PUT APIs primarily to update existing resource (if the resource does not exist then API may decide to create a new resource or not). If a new resource has been created by the PUT API, the origin server MUST inform the user agent via the HTTP response code 201 (Created)
response and if an existing resource is modified, either the 200 (OK)
or 204 (No Content
) response codes SHOULD be sent to indicate successful completion of the request.
If the request passes through a cache and the Request-URI identifies one or more currently cached entities, those entries SHOULD be treated as stale. Responses to this method are not cacheable .
Example request URIs
HTTP PUT http://www.appdomain.com/users/123
HTTP PUT http://www.appdomain.com/users/123/accounts/456
HTTP DELETE
As the name applies, DELETE APIs are used to delete resources (identified by the Request-URI).
A successful response of DELETE requests SHOULD be HTTP response code 200 (OK)
if the response includes an entity describing the status, 202 (Accepted)
if the action has been queued, or 204 (No Content)
if the action has been performed but the response does not include an entity.
DELETE operations are idempotent . If you DELETE a resource, it’s removed from the collection of resource. Repeatedly calling DELETE API on that resource will not change the outcome – however calling DELETE on a resource a second time will return a 404 (NOT FOUND) since it was already removed. Some may argue that it makes DELETE method non-idempotent. It’s a matter of discussion and personal opinion.
If the request passes through a cache and the Request-URI identifies one or more currently cached entities, those entries SHOULD be treated as stale. Responses to this method are not cacheable .
Example request URIs
HTTP DELETE http://www.appdomain.com/users/123
HTTP DELETE http://www.appdomain.com/users/123/accounts/456
HTTP PATCH
HTTP PATCH requests are to make partial update on a resource . If you see PUT requests also modify a resource entity so to make more clear – PATCH method is the correct choice for partially updating an existing resource and PUT should only be used if you’re replacing a resource in its entirety.
Please note that there are some challenges if you decide to use PATCH APIs in your application:
Support for PATCH in browsers, servers, and web application frameworks is not universal. IE8, PHP, Tomcat, Django, and lots of other software has missing or broken support for it.
Request payload of PATCH request is not straightforward as it is for PUT request. e.g. HTTP GET /users/1
produces below response:
{id: 1, username: 'admin', email: '[email protected] '}
A sample patch request to update the email will be like this:
HTTP PATCH /users/1
[ { “op”: “replace”, “path”: “/email”, “value”: “[email protected]” } ]
There may be following possible operations are per HTTP specification.
[ { "op": "test", "path": "/a/b/c", "value": "foo" }, { "op": "remove", "path": "/a/b/c" }, { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }, { "op": "replace", "path": "/a/b/c", "value": 42 }, { "op": "move", "from": "/a/b/c", "path": "/a/b/d" }, { "op": "copy", "from": "/a/b/d", "path": "/a/b/e" } ]
PATCH method is not a replacement for the POST or PUT methods. It applies a delta (diff) rather than replacing the entire resource.
Summary of HTTP Methods for RESTful APIs
Below table summarises the use of HTTP methods discussed above.
Glossary
Safe Methods
As per HTTP specification, the GET and HEAD methods should be used only for retrieval of resource representations – and they do not update/delete the resource on the server. Both methods are said to be considered “safe “.
This allows user agents to represent other methods, such as POST, PUT and DELETE , in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested – and they can update/delete the resource on server and so should be used carefully.
restfulapi.net
Введение
Здравствуйте, дорогие читатели! Прежде чем вы начнёте читать эту статью, я хотел бы описать цели её создания и рассказать, что побудило меня на её написание.
На одном из проектов нашей компании появилось необходимость спроектировать серверное приложение в стиле REST. Изначально нам казалось, что это довольно простая задача и для её решения нам хватит только собственного опыта.
Но, когда стартовал процесс разработки архитектуры и приведения REST-сервисов к единому стилю, у нас с коллегами начали возникать спорные вопросы и появляться разные точки зрения на реализацию того или иного аспекта. Тут мы поняли, что необходимо открыть гугл и обратиться к помощи коллективного разума, изучить предлагаемые лучшие практики, которые необходимо использовать при проектировании RESTful приложения.
Данная статья будет полезна для тех людей, которые уже имеют некоторый опыт работы с веб-приложениями (и возможно с REST-сервисами), но нуждаются в закреплении и стандартизации полученных знаний.
Определение
Для начала нужно определиться, что же такое REST. Википедия даёт на этот вопрос следующий ответ. REST (Representational State Transfer — «передача состояния представления») — архитектурный стиль взаимодействия компонентов распределённого приложения в сети. REST представляет собой согласованный набор ограничений, учитываемых при проектировании распределённой гипермедиа-системы.
Своими словами я бы объяснил понятие REST как “набор рекомендаций, который позволяет унифицировать взаимодействие клиентских и серверных приложений”. В данной статье я постараюсь рассказать об этих самых “рекомендациях”, которые помогут проектировать и создавать REST-сервисы согласно общепринятым практикам.
Также нужно понимать, что такое REST-сервис. Я бы дал определение REST-сервису, как “точка взаимодействия клиентского приложения с сервером”. Говоря Java терминологией — это сервлет, на который клиент посылает запрос.
Проблематика
Но прежде чем начинать описывать правила, я хотел бы донести мысль о том, что REST — это не стандарт, потому нет единых строгих правил, которых стоит придерживаться. Это значит, что до сих пор нет полной согласованности о том, какие решения лучше применять в той или иной ситуации. Очень часто заходят споры о том, какие HTTP методы использовать и какой HTTP код возвращать в каждой конкретной ситуации.
Более подробно о проблемах REST можно почитать тут. Соответственно, рекомендации, которые я опишу ниже, стоит принимать во внимание, но не следовать им на 100%, если это может повредить какому-либо другому аспекту проекта.
Однако если вы будете следовать всем рекомендациям, то получится спроектировать очень понятную и поддерживаемую систему, с которой приятно работать.
Название сервиса
Для начала необходимо выбрать имя для REST сервиса. Под именем сервиса я подразумеваю его путь в URI запросе. Например, http://my-site.by/api/rest/service/name. Для выбора имени нам нужно понимать что такое “ресурсы” в архитектуре REST.
Представление ресурса
В терминологии REST что угодно может быть ресурсом — HTML-документ, изображение, информация о конкретном пользователе и т.д. Если ресурс представляет собой некоторый объект, его легко представить, используя некоторый стандартный формат, например, XML или JSON. Далее сервер может отправить данный ресурс, используя выбранный формат, а клиент сможет работать с полученным от сервера ресурсом, используя этот же формат.
Пример представления ресурса “профиль” в формате JSON:
REST не накладывает явных ограничений на формат, который должен быть использован для представления ресурсов, но есть ряд правил, которым нужно следовать при разработке формата, который будет использоваться для представления ресурса:
Клиент и сервер должны “понимать” и иметь возможность работать с выбранным форматом.
Ресурс можно полностью описать, используя выбранный формат независимо от сложности ресурса.
Формат должен предусматривать возможность представления связей между ресурсами.
Пример представления ресурса “заказ” и его связи с ресурсом “профиль”:
Как видно, не обязательно полностью дублировать всю структуру ресурса, на который ссылается другой ресурс. Вместо этого можно использовать понятную ссылку на другой ресурс.
Обращение к ресурсу
Каждый ресурс должен быть уникально обозначен постоянным идентификатором. «Постоянный» означает, что идентификатор не изменится за время обмена данными, и даже когда изменится состояние ресурса. Если ресурсу присваивается другой идентификатор, сервер должен сообщить клиенту, что запрос был неудачным и дать ссылку на новый адрес. Каждый ресурс однозначно определяется URL. Это значит, что URL по сути является первичным ключом для единицы данных. То есть, например, вторая книга с книжной полки будет иметь вид /books/2 , а 41 страница в этой книге — /books/2/pages/41 . Отсюда и получается строго заданный формат. Причем совершенно не имеет значения, в каком формате находятся данные по адресу /books/2/pages/41 – это может быть и HTML, и отсканированная копия в виде jpeg-файла, и документ Word.
Рекомендуется при определении имени REST-сервиса использовать имена ресурсов во множественном числе. Такой подход позволяет добавлять новые REST-сервисы лишь расширяя имена уже существующих. Например, сервис /books вернёт нам список всех книг, /books/3 вернёт информацию о 3-ей книге, а сервис /books/3/pages вернёт все страницы 3-ей книги.
Для сервисов, которые выполняют какие-то специфические действия над ресурсом, есть 2 подхода для указания действия: в имени сервиса или в его параметрах. Например, /books/3/clean или /books/3?clean . Я предпочитаю первый вариант, так как обычно такие сервисы не редко используют POST методы, которые не поддерживают передачу параметров в URl, что делает сервис, на мой взгляд, не очень читабельным. Используя определение типа действия в имени сервиса, мы делаем наш сервис более расширяемым, так как он не зависит от типа HTTP метода.
Также очень не рекомендуется использовать имена, включающие в себя несколько слов и описывающие бизнес составляющую сервиса (как это рекомендуется делать при именовании java методов). Например, вместо /getAllCars лучше сделать метод /cars . Если же метод нельзя никак описать одним словом, то необходимо применять единый стиль разделителей, я обычно использую ‘-’, что является наиболее популярным подходом. Например, /cars/3/can-sold.
Более подробно о проектировании названий REST-сервисов можно прочитать в этой статье.
HTTP методы
Далее нам необходимо выбрать HTTP метод, который будет использовать наш REST-сервис, ведь имея даже одинаковое имя, но разные методы, REST-сервисы выполняют совершенно различные действия.
В REST используются 4 основных HTTP метода: GET, POST, PUT, DELETE. В большинстве случаев каждый из методов служит для выполнения предопределённого ему действия из CRUD (c reate, r ead, u pdate, d elete — «создание, чтение, обновление, удаление» ). POST — create, GET — read, PUT — update, DELETE — delete.
ВАЖНОЕ ДОПОЛНЕНИЕ: Существуют так называемые REST-Patterns, которые различаются связыванием HTTP-методов с тем, что они делают. В частности, разные паттерны по-разному рассматривают POST и PUT. Однако, PUT предназначен для создания, замены или обновления, для POST это не определено (The POST operation is very generic and no specific meaning can be attached to it). Поэтому иногда POST и PUT можно поменять местами. Но в большинстве случаев POST используют для создания, а PUT для редактирования, и чуть позже я объясню почему.
Приведу несколько примеров использования различных методов для взаимодействия с ресурсами.
GET /books/ – получает список всех книг. Как правило, это упрощенный список, т.е. содержащий только поля идентификатора и названия объекта, без остальных данных.
GET /books/{id} – получает полную информацию о книге.
POST /books/ – создает новую книгу. Данные передаются в теле запроса. PUT /books/{id} – изменяет данные о книге с идентификатором {id}, возможно заменяет их. Данные также передаются в теле запроса.
OPTIONS /books – получает список поддерживаемых операций для указанного ресурса (практически не используется)
DELETE /books/{id} – удаляет данные с идентификатором {id}.
Безопасность и идемпотентность
Очень помогут в выборе HTTP метода знания о безопасности и идемпотентности этих методов.
Безопасный запрос — это запрос, который не меняет состояние приложения.
Идемпотентный запрос — это запрос, эффект которого от многократного выполнения равен эффекту от однократного выполнения.
Судя по данной таблице, GET-запрос не должен менять состояние ресурса, к которому применяется. PUT и DELETE запросы могут менять состояние ресурса, но их можно спокойно повторять, если нет уверенности, что предыдущий запрос выполнился. В принципе, это логично: если многократно повторять запрос удаления или замены определенного ресурса, то результатом будет удаление или замена ресурса. Но POST запрос, как мы видим из таблицы, небезопасный и неидемпотентный. То есть мало того, что он меняет состояние ресурса, так и многократное его повторение будет производить эффект, зависимый от количества повторений. Ему по смыслу соответствует операция добавления новых элементов в БД: выполнили запрос Х раз, и в БД добавилось Х элементов.
Также приведу пример того, почему GET-запросы не должны изменять состояние ресурса. GET-запросы могут кэшироваться, например, на уровне прокси-сервера. В таком случае запрос может даже не дойти до сервера приложения, а в качестве ответа прокси-сервер вернёт информацию из кэша.
HTTP коды
В стандарте HTTP описано более 70 статус кодов. Хорошим тоном является использование хотя бы основных.
200 – OK – успешный запрос. Если клиентом были запрошены какие-либо данные, то они находятся в заголовке и/или теле сообщения.
201 – OK – в результате успешного выполнения запроса был создан новый ресурс.
204 – OK – ресурс успешно удалён.
304 – Not Modified – клиент может использовать данные из кэша.
400 – Bad Request – запрос невалидный или не может быть обработан.
401 – Unauthorized – запрос требует аутентификации пользователя.
403 – Forbidden – сервер понял запрос, но отказывается его обработать или доступ запрещен.
404 – Not found – ресурс не найден.
500 – Internal Server Error – разработчики API должны стараться избежать таких ошибок.
Эти ошибки должны быть отловлены в глобальном catch-блоке, залогированы, но они не должны быть возвращены в ответе.
Чем обширнее набор кодов, который мы будем использовать, тем более понятный будет API, который мы создаём. Однако нужно учесть, что некоторые коды браузеры обрабатывают по-разному. Например, некоторые браузеры получив код ответа 307 сразу же выполняют редирект, а некоторые позволяют обработать такую ситуацию и отменить действие. Прежде чем использовать тот или иной код, необходимо полностью понимать, как он будет обрабатываться на клиентской стороне!
Более подробно о HTTP кодах можно почитать тут.
Headers
Рекомендуется при проектировании REST-сервисов явно указывать заголовки, в которых обозначен формат обмена данными:
Content-Type — формат запроса;
Accept — список форматов ответа.
Параметры поиска ресурсов
Чтобы упростить использование сервисов, отвечающих за возвращение какой-либо информации, и вдобавок сделать их наиболее производительными, необходимо использовать в качестве параметров запроса параметры для сортировки, фильтрации, выбора полей и пагинации.
Фильтрация
Используйте уникальный параметр запроса для каждого поля, чтобы реализовать фильтрацию. Это позволит ограничить количество выводимой информации, что оптимизирует время обработки запроса.
Например, чтобы вывести все красные книги необходимо выполнить запрос:
GET /books?color=red
Сортировка
Сортировка реализуется подобно фильтрации. Например, чтобы вывести все книги, отсортированные по году публикации по убыванию и по названию по возрастанию нужно выполнить следующий запрос:
GET /books?sort=-year,+name
Пагинация
Для того, чтобы поддержать возможность загрузки списка ресурсов, которые должны отображаться на определённой странице приложения, в REST API должен быть предусмотрен функционал пагинации. Реализуется он с помощью знакомых нам по SQL параметрам limit и offset. Например:
GET /books?offset=10&limit=5
Помимо того хорошим тоном является вывод ссылок на предыдущую, следующую, первую и последнюю страницы в хидере Link. Например:
Link: <http://localhost/api/books?offset=15&limit=5>; rel=»next», <http://localhost/api/books?offset=50&limit=3>; rel=»last», <http://localhost/api/books?offset=0&limit=5>; rel=»first», <http://localhost/api/books?offset=5&limit=5>; rel=»prev»
Рекомендуется также возвращать общее количество ресурсов в хидере X-Total-Count.
Выбор полей ресурса
Для более удобного использования сервиса, для экономии трафика можно предоставить возможность управлять форматом вывода данных. Реализуется предоставлением возможности выбора полей ресурса, которые должен вернуть REST сервис. Например, если необходимо получить только id книг и их цвета, необходимо выполнить следующий запрос:
GET /books?fields=id,color
Хранение состояния
Одно из ограничений RESTful сервисов заключается в том, что они не должны хранить состояние клиента, от которого получают запросы.
Пример сервиса, не хранящего состояние: Request1: GET http://MyService/Persons/1 HTTP/1.1 Request2: GET http://MyService/Persons/2 HTTP/1.1
Каждый из этих запросов может быть обработан независимо от другого.
Пример сервиса, хранящего состояние: Request1: GET http://MyService/Persons/1 HTTP/1.1 Request2: GET http://MyService/NextPerson HTTP/1.1
Чтобы обработать второй запрос, серверу потребуется “запомнить” id последнего человека, который был запрошен клиентом. Т.е. сервер должен “запомнить” свое текущее состояние, иначе второй запрос не может быть обработан. При проектировании сервиса, следует избегать необходимости в хранении состояния, так как это имеет ряд преимуществ.
Преимущества сервиса, не хранящего состояние:
сервис обрабатывает запросы независимо друг от друга;
архитектура сервиса упрощается;
не требуется дополнительных усилий для реализации сервисов с использованием протокола HTTP, который также не хранит состояния.
Недостатки сервиса, не хранящего состояние:
клиент сам должен отвечать за передачу необходимого контекста сервису.
Версионность
Хорошим тоном является поддержка версионности REST API. Это позволит в дальнейшем легко расширять API, без обязательного внесения изменений в клиенты, которые уже пользуются им. Имеются несколько подходов реализации версионности:
С использованием Accept хидера. В данном случае версия API указывается в Accept — Accept:text/v2+json
С использованием URI. В таком подходе версия API указывается прямо в URI — http://localhost/api/v2/books
Использование кастомного хидера. Можно использовать собственный хидер, который будет отвечать только за передачу версии API — API-Version:v2
Использование параметра запроса. Можно использовать параметр запроса для передачи версии API — /books?v=2
Каждый из представленных способов имеет право на существование, у каждого есть свои плюсы и минусы. Однако только Вам решать, какой способ реализации версионности подойдёт Вашему проекту.
Документация
Для удобного пользования нашими REST сервисами нужно создать хорошую и понятную документацию. Для этих целей можно использовать различные инструменты, например, Mashape или Apiary, но я рекомендую использовать Swagger.
Swagger — это технология, которая позволяет документировать REST-сервисы. Swagger поддерживает множество языков программирования и фреймворков. Плюс, Swagger предоставляет UI для просмотра документации.
Получить более подробную информацию о Swagger можно по данной ссылке.
Архивирование
Для экономии трафика рекомендуется использовать архивирование, при передаче больших данных. Это сократит время выполнения запроса. В большинстве современных фреймворков данная функция реализована по умолчанию.
Кэширование
Также для сокращения запросов к БД и увеличения быстродействия наших REST сервисов рекомендуется применить механизм кэширования. Кэширование можно настраивать как на уровне сервера, так и в самом приложении, в зависимости от ситуации.
Кэшированием можно управлять используя следующие HTTP заголовки:
Date — дата и время создания ресурса.
Last Modified — дата и время последнего изменения ресурса на сервере.
Cache-Control — заголовок HTTP 1.1 используемый для управления кэшированием.
Age — время, прошедшее с момента последнего получения ресурса, заголовок может быть добавлен промежуточным (между клиентом и сервером) компонентом (например, прокси сервер)
Рекомендации по кэшированию:
Рекомендуется кэшировать статические ресурсы, такие как изображения, стили css, файлы javascript.
Не рекомендуется указывать большое время жизни кэша.
Динамическое содержимое должно кэшироваться на короткое время или не кэшироваться вообще.
Общие рекомендации
Тип представления ресурса
Хотя REST не накладывает явных ограничений на формат, который должен быть использован для представления ресурсов, наиболее популярными являются XML и JSON.
Существует множество библиотек в разных языках программирования для удобной работы с этими форматами. Несмотря на это, рекомендуется использовать именно JSON для представления ресурсов. Это более легкий, читабельный формат, с которым проще работать по сравнению с XML, а так же проще выполнять сериализацию/десериализацию объектов в различных языках программирования. Однако иногда для поддержки некоторых REST клиентов сервису необходимо поддерживать XML формат. В таком случае можно реализовать поддержку обоих форматов и указывать в параметре запроса, в каком формате должен быть представлен ответ.
Использование проверенных решений для авторизации
Используйте для авторизации проверенные и отработанные схемы. Не изобретайте свой велосипед с использованием md5 подписей данных и прочего, доверьтесь профессионалам в области защиты данных. Всё уже придумано за Вас: OAuth, OpenID, APIKeys.
Обработка исключений
При возникновении ошибочных ситуаций необходимо выводить отформатированную и понятную информацию. Это относится в первую очередь к статус коду в HTTP ответе. Ошибки в сервисах чаще всего относятся к двум типам:
4xx — ошибки клиента;
5xx — ошибки сервера.
В случае ошибки клиента, например, ошибки валидации какого-то из параметров запроса, в теле ответа рекомендуется передавать полезную информацию об ошибке: сообщение, описание, код (например в формате JSON). В случае ошибки сервера отправлять дополнительную информацию в теле ответа не всегда возможно, например, в случаях когда сервер не доступен.
Плохим тоном является вывод всего стэк трейса исключения. Рекомендуется для каждой исключительной ситуации иметь свой код. В дальнейшем при выводе информации об ошибке можно будет добавить ссылку на документацию, в которой данный код будет выступать уникальным идентификатором. Например:
jazzteam.org
REST выступает за представление состояния передачи
Это было записано Роем Филдингом в его докторской диссертации в 2000 году, где он описал существующую и современную веб-архитектуру как абстракцию.
Название было призвано вызывать представление о том, как ведет себя хорошо разработанное веб-приложение.
Рой описал REST на простом примере:
Рассмотрим сеть веб-страниц как виртуальную машину состояний.
Каждая страница представляет состояние:
1. Во-первых, пользователь получает первое состояние в виде индексного состояния.
2. Затем пользователь переходит через приложение, выбирая ссылку (здесь ссылка на страницу)
3. Результат передачи следующего состояния пользователю.
REST все еще не HTTP
Конечно, еще в 2000 году сеть уже работала на HTTP, и Рой со своими коллегами-инженерами много работали над этим.
Однако REST не определяет конкретные детали реализации системы и не определяет какой-либо синтаксис протокола.
Вполне возможно иметь архитектуру RESTful поверх протоколов, отличных от HTTP.
Например, CoAP (протокол ограниченного применения) является протоколом RESTful для встроенных устройств (Internet of Things) и предназначен для использования минимальных ресурсов как на устройстве, так и в сети.
Так зачем использовать REST?
Всемирная паутина основана на архитектуре REST.
Поэтому, если вы создаете API-интерфейс non-RESTful, который будет использоваться в Интернете, то вы получите неоптимальную систему.Не оптимальный в отношении оптимизированной архитектуры.
Это важно отметить, поскольку не-RESTful API может быть неоптимальным в сетевой архитектуре, но оптимальным для других проблем. Например, современные интерфейсные приложения могут иметь очень специфические потребности, следовательно, растет число библиотек сбора данных, таких как GraphQL или Falcor.
Итак, когда это API RESTful?
API является RESTful, когда он постоянно действует под ограничениями REST.
REST определяет 6 ограничений для достижения желаемой оптимизации системы:
Это ограничение основано на принципе разделения интересов.
Это позволяет компонентам развиваться независимо. Создавая наш API, он действует как сервер, обслуживающий большое количество клиентов.
Связь между клиентом и сервером должна быть без гражданства. Это означает, что каждый запрос от клиента к серверу должен содержать всю необходимую информацию для завершения транзакции.
Основным преимуществом этого ограничения является то, что система способна масштабироваться лучше, потому что серверу не нужно сохранять состояние клиента между запросами. Отсутствие необходимости запоминать информацию о состоянии клиента освобождает ресурсы сервера, поэтому он может обслуживать больше клиентов одновременно.
Наиболее эффективным сетевым запросом является тот, который не использует сеть.
Когда мы создаем наш API, он не должен игнорировать кеширование.
Чтобы иметь эффективное кэширование в сети, компоненты должны иметь возможность взаимодействовать через единый интерфейс. С единым интерфейсом полезная нагрузка может передаваться в стандартной форме.
Это означает, что любая информация, которая может быть названа, может быть ресурсом (изображение, документ или даже набор других ресурсов)
Ресурс может быть представлен различными способами.
Например, HTML, XML, JSON или даже JPEG-файл.
Это правило означает, что клиенты взаимодействуют с ресурсами через свои представления, что является мощным средством удержания абстрактных понятий ресурсов от их взаимодействий.
Это означает, что ресурс может быть описан в сообщении запроса, а сервер может отвечать описательными сообщениями о состоянии. Да, HTTP-заголовки и коды ответов являются хорошими реализациями для этого правила.
Это на самом деле означает, что приложение должно управляться ссылками, позволяя клиентам обнаруживать ресурсы через гиперссылки.
Как вы можете видеть, многие из этих правил могут быть реализованы в протоколе HTTP. Поэтому, когда API использует HTTP правильно, это огромный шаг к тому, чтобы стать RESTful.
В многоуровневой системе посредники, такие как прокси-серверы, могут размещаться между клиентом и сервером, используя единообразный интерфейс сети.
Одним из преимуществ многоуровневой системы является то, что посредники могут затем перехватывать трафик клиент-сервер для определенных целей/ Например, для кэширования.
Это необязательное ограничение и позволяет клиентам загружать программы для выполнения на стороне клиента. Лучший пример для этого — интерфейсные JavaScript-приложения. Это может показаться нам сейчас очень очевидным, но в раннем возрасте Интернета это была эволюционирующая концепция, и это полезная часть интернет-архитектуры.
Правильно использовать HTTP
Если вы строите RESTful API, используйте протокол RESTful. Для Интернета HTTP-протокол является определенным выбором. Создайте свой API, чтобы он правильно использовал HTTP.
Создайте единый интерфейс
Сопоставьте свои концепции с ресурсами и назначьте соответствующие идентификаторы для каждого из них. Простым примером может служить служба базы данных пользователей. В такой службе мы можем назвать два ресурса; Пользователей и пользователей (ресурс сбора). Эти ресурсы могут быть идентифицированы с URI / users и / user / {id} URI вашего интерфейса API.
Управляйте своим API-гиперссылками
Используйте ссылки для подключения ваших ресурсов. Это сделает ваш API доступным для клиентов, которые имеют очень мало первоначальных знаний о ваших ресурсах.
Помните об архитектуре REST
Для меня главное избавление от создания RESTful API заключается в том, насколько важно понимать Интернет и его базовую архитектуру. Мы можем либо воспользоваться этой оптимизацией, либо мы можем игнорировать ее.
Если у вас появились какие-либо вопросы, приглашаем на наши курсы Java EE.
Спасибо, что прочитали мой пост. Обратная связь и мысли всегда приветствуются в разделе комментариев.
imprium.ru
Коротко обо мне
Меня зовут Зел, я разработчик-фрилансер из Сингапура. В свободное от работы время я люблю разбираться в коде и попутно публиковать в своем блоге те интересности, которые я обнаружил или изучил.
Вступление
Скорее всего вам уже приходилось слышать о таком термине, как REST API, особенно если вы сталкивались с необходимостью получения данных из другого источника (такого как Twitter или Github). Но что же все-таки это такое? Что мы можем с этим делать и как мы можем это использовать?
В данной статье вы узнаете все о REST API для того, чтобы работать с ними и читать связанную с ними документацию.
Что же такое REST API ?
Давайте представим, что вы пытаетесь найти фильмы о Бэтмене на YouTube. Вы открываете сайт, вбиваете в форму поиска слово «Бэтмен», жмакаете «Окей» и видите список фильмов о супергерое. Похожим образом работает и WEB API. Вы ищите что-то и получаете список результатов от запрашиваемого ресурса.
Дословно API расшифровывается как Application Programming Interface. Это набор правил, позволяющий программам «общаться» друг с другом. Разработчик создает API на сервере и позволяет клиентам обращаться к нему.
REST – это архитектурный подход, определяющий, как API должны выглядеть. Читается как «Representational State Transfer». Этому набору правил и следует разработчик при создании своего приложения. Одно из этих правил гласит, что при обращении к определенному адресу, вы должны получать определенный набор данных (ресурс).
Каждый адрес маршрутом, пакет данных — запросом, в то время как результатирующий ресурс – ответом.
Анатомия запроса
Важно понимать структуру запроса:
Маршрут отправки
Тип метода
Заголовки
Тело (или данные)
Маршрут – это адрес, по которому отправляется ваш запрос. Его структура примерно следующая:
Root-endpoint — это точка приема запроса на стороне сервера (API). К примеру, конечная точка GitHub – https://api.github.com.
Путь определяет запрашиваемый ресурс. Это что-то вроде автоответчика, который просит вас нажать 1 для одного сервиса, 2 для другого и так далее.
Для понимания того, какие именно пути вам доступны, вам следует просмотреть документацию. К примеру, предположим, вы хотите получить список репозиториев для конкретного пользователя на Git. Согласно документации, вы можете использовать следующий путь для этого:
Вам следует подставить под пропуск имя пользователя. К примеру, чтобы найти список моих репозиториев, вы можете использовать маршрут:
Последняя часть маршрута – это параметры запроса. Технически запросы не являются частью REST-архитектуры, но на практике сейчас все строится на них. Так что давайте поговорим о них более детально. Параметры запроса позволяют использовать в запросе наборы пар «ключ-значение». Они всегда начинаются знаком вопроса. Каждая пара параметров после чего разделяется амперсантом (что-то вроде этого):
Как только вы пытаетесь получить список репозиториев для пользователя, вы добавляете эти три опциональных параметра и после чего получаете следующий результат:
Если же вы желаете получить список моих недавно запушеных репозиториев, вам следует ввести следующее:
Итак, как же понять, что маршруты рабочие? Что ж, пришло время проверить их на практике!
Тестирование при помощи Curl
Вы моете отправить запрос при помощи любого языка программирования. JavaScript может использовать методы вроде Fetch API или JQuery`s Ajax Method. Руби использует другое. И так далее.
В этой статье я буду использовать такую утилитку, как Curl. Дело в том, что она указана в официальной документации для веб-сервисов. Если вы поймете, как использовать эту утилиту, вы поймете, как работать с API. После чего вы можете производить запросы любым удобным для вас языком.
Перед тем, как продолжить, вам следует убедится, что Curl установлен на вашей машине.
Ели же он не установлен, самое время установить. В таком случае вы получите ошибку «command not found».
Для того, чтобы использовать утилиту, необходимо ввести следующее (по примеру):
И как только вы подтверждаете ввод, вы получаете ответ (наподобие этого):
Чтобы получить список пользовательских репозиториев, вам следует изменить запрос по тому же принципу, который был оговорен ранее. К примеру, чтобы получить список моих репозиториев, вам следует ввести следующее:
Если же вы желаете включить параметры запросов, убедитесь, что вы их экранируете. Дело в том, что без экранирования знаки вопроса и равно расцениваются системой как спец. символы и выполнение команды произойдет с ошибкой.
Также попробуйте другие команды и произведите запросы! В результате вы получаете похожие ответы.
JSON
JSON – JavaScript Object Notation – общий формат для отправки и приема данных посредством REST API. Ответ, отправляемый Github, также содержится в формате JSON.
Содержание объекта этого формата примерно следующее:
Возвращаемся к анатомии запроса
Вы изучили, что запрос состоит из четырех частей:
Маршрут отправки
Тип метода
Заголовки
Тело (или данные)
Теперь же давайте попробуем разобраться с остальным.
Тип метода
Метод обозначает тип производимого запроса, де-факто он является спецификацией операции, которую должен произвести сервер. Всего существует пять типов запросов:
GET
POST
PUT
PATCH
DELETE
GET – используется для получения со стороны севера определенного ресурса. Если вы производите этот запрос, сервер ищет информацию и отправляет ее вам назад. По сути, он производит операцию чтения на сервере. Дефолтный тип запросов.
POST – нужен для создания определенного ресурса на сервере. Сервер создает в базе данных новую сущность и оповещает вас, был ли процесс создания успешным. По сути, это операция создания.
PUT и PATCH – используются для обновления определенной информации на сервере. В таком случае сервер просто изменяет информацию существующих сущностей в базе данных и оповещает об успехе выполнения операции.
DELETE – как и следует из названия, удаляет указанную сущность из базы или сигнализирует об ошибке, если такой сущности в базе не было.
Сам же API позволяет указать, какой метод должен быть использован в определенных контекстных ситуациях.
GET запрос в этом случае необходим, чтобы получить список всех репозиториев указанного пользователя. Также можно использовать curl:
Попробуйте отправить этот запрос. В качестве ответа вы получите требование об аутентификации.
Заголовки
Заголовки используются, чтобы предоставить информацию как клиенту, так и серверу. Вообще, их можно использовать для много чего – пример – та же самая аутентификация и авторизация. Найти список доступных заголовком можно на официальной странице MDN.
Заголовки представляют из себя пары ключей-значений. Пример:
Также пример с использованием curl:
(Примечание: заголовок Content-Type в случае Github для работы не является обязательным. Это всего лишь пример использования заголовка в запросе, ничего более.)
Для просмотра отправленных заголовком можно использовать следующее:
Здесь звездочка относится к дополнительной информации, предоставленной посредством curl. > относится к заголовкам запроса, а <, соответственно, — к заголовкам ответа.
Чтобы отправить информацию с curl, используйте следующее:
Для отправки множественных полей, мы можем использовать несколько подобных конструкций:
Также, если необходимо, вы можете разбить ваш запрос на несколько линий для обеспечения большей читабельности:
Если вы знаете, как развернуть сервер, вы можете создать собственный API и протестировать свои запросы. Если же нет, обязательно попробуйте. Существует множество информации, посвященной этому.
Если же желания разворачивать свой сервер нет, попробуйте бесплатную опцию Request bin.
После чего вы получите адрес, который спокойно сможете тестировать.
Убедитесь, что вы создаете свой собственный request bin, если вы хотите протестировать именно ваш запрос. Учитывайте, что дефолтное время существования request bin – 48 часов. Потому те примеры адресов, которые я здесь привожу, на момент прочтения статьи давно как устарели.
Теперь же попробуйте отправить некоторую информацию, после чего обновите свою страницу.
Если все пройдет успешно, вы увидите следующее:
По умолчанию curl отправляет данные так, как если бы они были отправлены посредством полей форм. Если вы хотите отправить данные через JSON, ваш Content-Type должен равняться applicationjson, впоследствии вам необходимо отформатировать данные в виде JSON-объекта.
По сути, это все, что вам необходимо знать о структуре запроса.
Теперь давайте вспомним об аутентификации. Что же это такое и для чего она нужна?
Аутентификация
Вы бы не позволили никому чужому получить доступ к вашему банковскому счету без специального разрешения, не так ли? По такому же принципу разработчики не позволяют неавторизированным пользователям производить на сервере все, что им вздумается.
Так как POST, PUT, PATCH, DELETE запросы изменяют базу данных, разработчики должны всегда быть на страже неавторизированного доступа к ним. Впрочем иногда GET запросы также требуют аутентификации (к примеру, когда вы желаете посмотреть состояние вашего банковского счета).
В случае с вебом существует два способа представиться системе:
Через ник и пароль (базовая аутентификация)
Через секретный токен
Секретный токен позволяет представить вас системе через соц. Сети по типу Github, Google, Twitter и так далее.
Здесь же я рассмотрю только базовую аутентификацию.
Для произведения базовой аутентификации вы можете использовать следующее:
Попробуйте залогиниться под свой профиль по запросу, указанному выше. Как только вы успешно войдете в свой профиль, вы увидите ответ «problems parsing JSON».
Почему? Все просто: системе-то вы представились, но – вот беда – ничего полезного ей не предоставили. Все типы запросов требуют определенной информации.
Теперь же давайте поговорим о статус-кодах и возможных ошибках.
Статус-коды и возможные ошибки
Некоторые из сообщений, приведенных выше, как раз-таки и относятся к кодам ошибок. Логично, что они появляются только, когда что-то идет не совсем так, как было запланировано. Что же касательно статуса кодов, они позволяют вам познать успех (или неудачу) при выполнении определенного запроса. Бывают статус-коды от 100 до 500+. В целом их можно разделить на следующие группы:
200+: запрос успешен
300+: запрос перенаправлен на другой маршрут
400+: ошибка на стороне клиента
500+: ошибка на стороне сервера
Вы можете отладить статус ответа при помощи –v или –verbose. К примеру, я попытался получить доступ к определенному ресурсу без авторизации. Следовательно, я поймал ошибку:
В случае же, когда запрос не верен по причине ошибки в самой передаваемой информации, вы получаете статус-код 400:
Версии API
Время от времени разработчики обновляют свои API. Порой обновления могут быть такими сильными, что разработчик желает выпустить релиз новой версии. В таком случае, если ваше приложение ломается, это происходит по причине, что вы писали код с учетом старого компонента, тогда как новый несколько отличается в плане реализации.
Запросить текущую версию API можно двумя путями.
Через маршурт
Через заголовок
К примеру, Твиттер использует первый метод. На момент написания версия Твиттер API была 1.1.
С другой стороны, GitHub использует другой способ:
В заключение
В этой статье мы рассмотрели, что такое REST API и как его можно использовать совместно с curl. Кроме того, вы также выучили, как залогиниться при помощи запроса и что такое статус-код.
Я искренне надеюсь, что эта статья позволила вам повысить свой уровень общих и не очень познаний касательно такого немаловажного аспекта веб-разработки. Буду рад любым вашим комментариям здесь.
Автор перевода: Евгений Лукашук
Источник
itvdn.com