Статьи

Обнаружение API REST и HATEOAS

Это четвертая серия статей о настройке защищенного веб-сервиса RESTful с использованием Spring 3.1 и Spring Security 3.1 с настройкой на основе Java. Статья будет посвящена Обнаруживаемости REST API, HATEOAS и практическим сценариям, основанным на тестах.

ОТДЫХ с весенней серией:

Представляем REST Discoverability

D iscoverability из 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 в ответе:

@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, ресурс должен быть доступен:

@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 :

@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 Обнаружение от REST с серией Spring .