Представляем REST Discoverability
Обнаруживаемость API — это тема, которая не получает достаточно заслуженного внимания, и, как следствие, очень немногие API понимают это правильно. Это также то, что, если все сделано правильно, может сделать API не только RESTful и удобным, но и элегантным.
Чтобы понять обнаруживаемость , нужно понять это ограничение, которое является гипермедиа как движок состояния приложения (HATEOAS); это ограничение API RESTful касается полной возможности обнаружения действий / переходов на ресурсе из гипермедиа (действительно, гипертекст), как единственного драйвера состояния приложения. Если взаимодействие должно осуществляться API через сам диалог, конкретно через гипертекст, тогда не может быть документации , поскольку это заставит клиента делать предположения, которые на самом деле находятся вне контекста API.
Кроме того, продолжая этот логический ход мысли, единственный способ, которым API действительно может считаться RESTful, — это если он полностью обнаруживаем из корня и не имеет предварительных знаний — это означает, что клиент должен иметь возможность перемещаться по API, выполняя GET на корень. В дальнейшем все изменения состояния осуществляются клиентом с использованием доступных и обнаруживаемых переходов, которые REST API предоставляет в представлениях (следовательно, передача состояния представлений ).
В заключение, сервер должен быть достаточно информативным, чтобы указывать клиенту, как использовать API только через гипертекст, который, в случае HTTP-разговора, может быть заголовком Link .
Конкретные сценарии обнаружения (управляемые тестами)
Так что же означает, что служба REST может быть обнаружена ? В этом разделе мы будем тестировать отдельные признаки обнаруживаемости, используя Junit, rest-assured и Hamcrest . Поскольку служба REST была защищена в части 3 серии , каждый тест должен сначала пройти аутентификацию перед использованием API. Некоторые утилиты для анализа заголовка ссылки ответа также необходимы.
Откройте для себя действительные методы HTTP
Когда веб-служба RESTful используется с недопустимым методом HTTP , ответ должен быть 405 МЕТОД НЕ РАЗРЕШЕН ; Кроме того, это также должно помочь клиенту найти допустимые методы HTTP, которые разрешены для этого конкретного ресурса, используя заголовок Allow HTTP в ответе:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@Test public void whenInvalidPOSTIsSentToValidURIOfResource_thenAllowHeaderListsTheAllowedActions(){ // Given final String uriOfExistingResource = this .restTemplate.createResource(); // When Response res = this .givenAuthenticated().post( uriOfExistingResource ); // Then String allowHeader = res.getHeader( HttpHeaders.ALLOW ); assertThat( allowHeader, AnyOf.<String> anyOf( containsString( "GET" ), containsString( "PUT" ), containsString( "DELETE" ) ) ); } |
Откройте для себя URI вновь созданного ресурса
Операция создания нового ресурса всегда должна включать в ответ URI вновь созданного ресурса с использованием заголовка HTTP местоположения . Если клиент выполняет GET для этого URI, ресурс должен быть доступен:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@Test public void whenResourceIsCreated_thenURIOfTheNewlyCreatedResourceIsDiscoverable(){ // When Foo unpersistedResource = new Foo( randomAlphabetic( 6 ) ); Response createResponse = this .givenAuthenticated().contentType( MIME_JSON ) .body( unpersistedResource ).post( this .paths.getFooURL() ); final String uriOfNewlyCreatedResource = createResp .getHeader( HttpHeaders.LOCATION ); // Then Response response = this .givenAuthenticated() .header( HttpHeaders.ACCEPT, MIME_JSON ).get( uriOfNewlyCreatedResource ); Foo resourceFromServer = response.body().as( Foo. class ); assertThat( unpersistedResource, equalTo( resourceFromServer ) ); } |
Тест проводится по простому сценарию: создается новый ресурс Foo, а HTTP-ответ используется для обнаружения URI, где теперь доступен ресурс. Затем тесты продвигаются на один шаг вперед и выполняют GET для этого URI, чтобы извлечь ресурс и сравнить его с оригиналом, чтобы убедиться, что он был правильно сохранен.
Откройте для себя URI, чтобы получить все ресурсы этого типа
Когда мы ПОЛУЧАЕМ конкретный экземпляр Foo , мы должны быть в состоянии обнаружить, что мы можем делать дальше: мы можем перечислить все доступные ресурсы Foo . Таким образом, операция извлечения ресурса всегда должна включать в свой ответ URI, где получить все ресурсы этого типа, снова используя заголовок Link :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
@Test public void whenResourceIsRetrieved_thenURIToGetAllResourcesIsDiscoverable(){ // Given String uriOfExistingResource = this .restTemplate.createResource(); // When Response getResponse = this .givenAuthenticated().get( uriOfExistingResource ); // Then String uriToAllResources = HTTPLinkHeaderUtils.extractURIByRel ( getResponse.getHeader( "Link" ), "collection" ); Response getAllResponse = this .givenAuthenticated().get( uriToAllResources ); assertThat( getAllResponse.getStatusCode(), is( 200 ) ); } |
Тест затрагивает сложную тему отношений связей в REST: URI для извлечения всех ресурсов использует семантику rel = ”collection” . Этот тип связи еще не стандартизирован, но уже используется несколькими микроформатами и предлагается для стандартизации. Использование нестандартных отношений ссылок открывает дискуссию о микроформатах и более богатой семантике в веб-сервисах RESTful.
Другие потенциальные обнаруживаемые URI и микроформаты
Другие URI потенциально могут быть обнаружены через заголовок Link , но существует только столько, сколько позволяют существующие типы отношений ссылок без перехода к более богатой семантической разметке, такой как определение пользовательских отношений ссылок , протокол публикации Atom или микроформаты , которые будут темой другой статьи.
Например, было бы хорошо, если бы клиент мог обнаружить URI для создания новых ресурсов при выполнении GET для определенного ресурса; к сожалению, нет никакого отношения ссылки к семантике создания модели. К счастью, стандартная практика заключается в том, что URI для создания такой же, как URI для получения всех ресурсов этого типа, с единственным отличием — это метод POST HTTP.
Вывод
В этой статье были рассмотрены некоторые признаки обнаруживаемости в контексте веб-службы RESTful, обсуждается обнаружение методов HTTP, связь между созданием и получением, обнаружением URI для получения всех ресурсов и т. Д. В следующих статьях я сосредоточусь на обнаружение API, начиная с корня , разбиения на страницы, пользовательских отношений ссылок, протокола публикации Atom и фактической реализации Discoverability в службе REST с помощью Spring. В то же время, проверьте проект GitHub .
Ссылка: Обнаружение веб-службы RESTful, часть 4 от нашего партнера JCG Евгения Параскива в блоге baeldung .
Статьи по Теме :
- Начальная загрузка веб-приложения с помощью Spring 3.1 и конфигурации на основе Java, часть 1
- Создание веб-службы RESTful с использованием Spring 3.1 и конфигурации на основе Java, часть 2
- Защита веб-службы RESTful с помощью Spring Security 3.1, часть 3
- Обнаружение службы REST с помощью Spring, часть 5
- Базовая и дайджест-аутентификация для службы RESTful с Spring Security 3.1, часть 6
- Интеграция Spring & Quartz с пользовательской аннотацией
- Пример Spring MVC Interceptors
- Обмен конфигурации Spring Bean во время выполнения