引入REST可發現性
API的可發現性是一個值得引起足夠關注的主題,因此很少有API能夠正確地實現它。 如果做得正確,這也可以使API不僅具有RESTful和可用性,而且具有優雅的風格。
要了解可發現性 ,需要了解這種約束,即“超媒體作為應用程序狀態引擎(HATEOAS)”; RESTful API的這種約束是關于作為應用程序狀態唯一驅動程序的超媒體(實際上是超文本)對資源上的動作/轉換的完全可發現性。 如果交互作用是由API通過對話本身(特別是通過超文本)來驅動的,那么就沒有文檔 ,因為這會迫使客戶端做出實際上不在API上下文之外的假設。
此外,繼續這種邏輯思路,確實可以認為RESTful API的唯一方法是,如果它可以從根完全發現并且沒有先驗知識 ,這意味著客戶端應該能夠通過在GET上進行GET來導航API。根。 展望未來,所有狀態更改均由客戶端使用REST API在表示形式中提供的可用且可發現的轉換來驅動(因此稱為Representational State Transfer )。
總之,服務器應具有足夠的描述性,以指示客戶端如何僅通過超文本來使用API??,在HTTP對話的情況下,該超文本可能是Link標頭。
具體的可發現性場景(由測試驅動)
那么,REST服務可被發現意味著什么? 在本節中,我們將使用Junit, rest-assured和Hamcrest來測試可發現性的各個特征。 由于REST Service已在該系列的第3部分中得到保護,因此在使用API??之前,每個測試都需要首先進行身份驗證 。 還需要一些實用程序來解析響應的Link標頭。
發現有效的HTTP方法
當使用無效的HTTP方法使用RESTful Web服務時,響應應為405 METHOD NOT ALLOWED ; 此外,它還應該使用響應中的“ 允許 HTTP標頭”來幫助客戶端發現該特定資源所允許的有效HTTP方法:
@Test
public void whenInvalidPOSTIsSentToValidURIOfResource_thenAllowHeaderListsTheAllowedActions(){// Givenfinal String uriOfExistingResource = this.restTemplate.createResource();// WhenResponse res = this.givenAuthenticated().post( uriOfExistingResource );// ThenString allowHeader = res.getHeader( HttpHeaders.ALLOW );assertThat( allowHeader, AnyOf.<String> anyOf( containsString("GET"), containsString("PUT"), containsString("DELETE") ) );
}
發現新創建的資源的URI
使用位置 HTTP標頭,創建新資源的操作應始終在響應中包括新創建資源的URI。 如果客戶端在該URI上執行GET,則該資源應可用:
@Test
public void whenResourceIsCreated_thenURIOfTheNewlyCreatedResourceIsDiscoverable(){// WhenFoo 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 );// ThenResponse response = this.givenAuthenticated().header( HttpHeaders.ACCEPT, MIME_JSON ).get( uriOfNewlyCreatedResource );Foo resourceFromServer = response.body().as( Foo.class );assertThat( unpersistedResource, equalTo( resourceFromServer ) );
}
該測試遵循一個簡單的場景:創建一個新的Foo資源,并使用HTTP響應來發現該資源現在可訪問的URI 。 然后,測試會更進一步,并對該URI進行GET檢索以獲取資源并將其與原始資源進行比較,以確保資源已正確保留。
發現URI以獲取該類型的所有資源
當我們獲取特定的Foo實例時,我們應該能夠發現下一步可以做什么:我們可以列出所有可用的Foo資源。 因此,獲取資源的操作應始終在其響應中包含URI,以在何處獲取該類型的所有資源,再次使用Link標頭:
@Test
public void whenResourceIsRetrieved_thenURIToGetAllResourcesIsDiscoverable(){// GivenString uriOfExistingResource = this.restTemplate.createResource();// WhenResponse getResponse = this.givenAuthenticated().get( uriOfExistingResource );// ThenString uriToAllResources = HTTPLinkHeaderUtils.extractURIByRel( getResponse.getHeader( "Link" ), "collection" );Response getAllResponse = this.givenAuthenticated().get( uriToAllResources );assertThat( getAllResponse.getStatusCode(), is( 200 ) );
}
該測試解決了REST中鏈接關系的一個棘手問題:要檢索所有資源的URI使用rel =“ collection”語義。 這種類型的鏈接關系尚未標準化,但已被多種微格式使用 ,并已提出標準化要求。 非標準鏈接關系的使用打開了有關RESTful Web服務中的微格式和更豐富語義的討論。
其他可能發現的URI和微格式
其他URI可能會通過Link標頭發現,但是在沒有轉移到更豐富的語義標記(例如定義 自定義鏈接關系 , Atom發布協議或微格式)的情況下 ,現有的鏈接關系類型只有這么多。另一篇文章。
例如,如果在特定資源上執行GET時客戶端可以發現URI來創建新資源,那將是一個很好的選擇。 不幸的是,與模型創建語義沒有鏈接關系。 幸運的是,標準做法是創建的URI與獲取該類型的所有資源的URI相同,唯一的區別是POST HTTP方法。
結論
本文介紹了RESTful Web服務上下文中可發現性的一些特征,討論了HTTP方法發現,創建和獲取之間的關系,發現URI以獲取所有資源的關系等。在接下來的文章中,我將重點介紹從root ,分頁,自定義鏈接關系,Atom發布協議以及Spring REST服務中的Discoverability的實際實現開始發現API。 同時,檢查github項目 。
參考: RESTful Web服務可發現性,我們的JCG合作伙伴 Eugen Paraschiv在baeldung博客上的第4部分 。
相關文章 :
- 使用Spring 3.1和基于Java的配置引導Web應用程序,第1部分
- 使用Spring 3.1和基于Java的配置構建RESTful Web服務,第2部分
- 使用Spring Security 3.1保護RESTful Web服務,第3部分
- Spring的REST服務發現性,第5部分
- 使用Spring Security 3.1的RESTful服務進行基本身份驗證和摘要身份驗證,第6部分
- Spring&Quartz集成自定義注釋
- Spring MVC攔截器示例
- 在運行時交換出Spring Bean配置
翻譯自: https://www.javacodegeeks.com/2011/12/restful-web-service-discoverability.html