2016-07-22 19 views
1

好的,所以我們都知道獲取所有實體列表的REST方式是HTTP/GET /entities,獲取單個實體的最佳方式是HTTP/GET /entities/{entityId}和獲得一些實體的最佳方式是HTTP/GET /entities/{entityId}?where=condition(*)對不對?用於檢索元素的特定子集的REST最佳實踐

(*)其實我的意思是/entities?where=condition

但是這將是一個很好的方法,當我們需要得到一個特定的實體組,相當於一個SQL select ... where id in(id1, id2...)當多個HTTP/GET entities/{entityId}是不是由於一個選項潛伏?

而具體我將如何能夠與的RESTEasy

+0

難道不是另一個條件嗎?爲什麼不使用/實體?id = id1,id2,id3 – sancho21

+0

REST與您的URI設計幾乎沒有任何關係!另外,'/ entities/{entityId}?where = condition'我卑微的意義應該返回一個實體的某個子集,而不是一組實體。 –

+0

@RomanVottner我並不真的看到它那樣。大多數API都面臨着我所描述的工作(也許我曾與錯誤的工作)。另外我不明白你的意思是一個實體的子集? –

回答

1

雖然你已經找到了解決辦法,因爲我的原因不能接受的答案我在下面解釋的忠實粉絲,我會發佈一個答案。誠然,這是一個非常自以爲是的答案,因爲HTTP規範允許多種方式來實現類似的事情,而REST並不規定某種URI風格,也爲語義解釋留下了許多擺動空間。

對於可能的URI參數的語義,超文本傳輸​​協議(HTTP)不是非常具有描述性。 pathquery這些參數大家都知道,headermatrix參數經常被忽略,儘管JAX-RS(就像您最初要求的RESTeasy一樣)可以像處理其他參數那樣容易地處理它們。

REST此外是一種架構風格而不是協議。要調用服務(或API)RESTful,它必須遵守幾個constraints以及尊重底層的HTTP協議。由於REST是以資源爲導向的,所以使用唯一的資源標識符來調用相應的資源(因此是URI)。但是,REST並未對URI的設計方式施加任何限制。人們傾向於將一些語義上的意義放入一個好的URI中,但對於計算機來說,它只是一個進一步的字符串。

在你的評論中寫道:

我真的不這麼認爲。大多數API都面臨着我所描述的工作(也許我曾與錯誤的工作)。

對我的評論,/entites/{entityId}?where=condition返回一個指定實體的子集而不是實體的子集。通過在URI中指定{entityId}作爲路徑參數,您已將結果集限制爲單個實體。如果您打算返回一組符合特定實體屬性的實體,爲什麼還要提供{entityId}

查詢參數被附加到URI的末尾,因此與矩陣參數f.e相比,屬於每個單獨的路徑段。它們僅屬於單個路徑段,因此在具有多個路徑段的較長URI上傳遞稍微不同的語義。在不包含子資源的簡單URI上,矩陣參數和查詢參數之間的差異相當小,它們都可以交換使用。不過,對於具有多個路徑段的URI,語義可能會發生變化。

此外,我不明白你的意思是一個實體的子集?

如果您有與ID USER1像下面的一個用戶實體JSON表示:

{ 
    "firstName": "Tim", 
    "lastName": "Sample", 
    "address": { 
     "street": "...", 
     "zip": "...", 
     "city": "...", 
     "country": "..." 
    } 
} 

調用GET /user/user1?filter=lastName我期望的查詢,通過address F.E.只返回{ "lastName": "Sample" },在濾波我希望只有地址子資源才能返回,儘管在這種情況下我會使用/users/user1/address。類似GET /user/user1?lastName=Sample可能會被解釋爲檢查,如果識別的用戶具有提供的名稱,因此應返回true或false作爲響應。正如你所看到的,人類在語義上解釋URI或它們的參數,而對於計算機,URI只包含子字符串,並且他們不關心參數是否作爲path-,query-,matrix-或者header參數提供。他們僅僅依靠一些預定義的指令來告訴他們從哪裏提取所需的信息。

我對接受的解決方案的擔憂是,在使用POST時,您可以直接向服務器發送任何內容。因此,您需要明確記錄需要發送給服務的預期表示以及服務器在接收到請求後執行的行爲。此外,在使用POST進行查詢時,您將無法緩存響應。後者是REST擁有的few constraints之一。雖然某些緩存框架不會在包含查詢參數的URI上緩存響應,但是this link以及this answer都表明這更像是一個城市傳說,然後是現實。

當然,您可以實現服務器端緩存以儘量減少數據庫查找,但請求仍然會到達服務器。在使用GET而不是POST時,由於客戶端能夠緩存答案(如果不通過特殊響應頭設置阻止),因此請求甚至不會連續到達服務器,因此直接從緩存返回答案而不是查看狀態一次又一次。

但是這將是一個很好的方法,當我們需要獲取特定的實體組,相當於一個SQL SELECT ...其中id在(ID1,ID2 ...)當多個HTTP/GET實體/由於延遲,{entityId}不是一個選項嗎?

an other post所述,可以在路徑段上指定矩陣參數,而不是在整個URI上指定矩陣參數,如查詢參數。這使得它們對URI的某些部分進行過濾非常有用。如果你想返回f.e.所有由灰色頭髮顏色的教授舉辦的課程可以使用GET /professors;haircolor=grey/courses之類的內容。你當然可以扭轉結構並使用類似/courses/professors?haircolor=grey這樣的語法上完全沒問題,但如果你考慮哪些資源可以更容易地存在,而不是更容易使用這些資源,並且在更多的依賴資源之前使用這些資源,那麼最終可能會得到前一個URI。

因此,針對您的問題的可能解決方案可能如下所示:GET /entity;id={id1};id={id2};...。正如在this answer中所解釋的那樣,在單個資源上使用查詢或矩陣參數可能不會有很大的區別,但是如果你是f.e.想要返回指定用戶組的所有地址,只有您可以使用類似這樣的內容:GET /users;id={id1};id={id2}/addresses。這允許您在使用HTTP GET時進行響應緩存,同時您還在語義上使用資源子資源語法,其中在引用資源之前使用了更有可能不存在另一個的資源子資源語法。

由於RESTeasy能夠使用JAX-RS,因此可以使用@MatrixParam批註方便地將矩陣參數注入方法參數。與@QueryParam@PathParam參數一樣,基礎JAX-RS框架將盡力嘗試convert the parameter以盡力而爲。

@GET 
public Response getSomething(@MatrixParam List<String> ids) { 
    ... 
} 

在情況下參數不能被整理到自動的對象,也可以使用@Context註解注入一個UriInfo對象,然後經由相應的PathSegment該參數上註解,然後編組檢索矩陣參數它對你自己的一個對象。

@GET 
public Response getSomething(@Context UriInfo info) { 
    for (PathSegment segment : info.getPathSegments()) { 
     MultivaluedMap matrixParameters = segment.getMatrixParameters(); 
     ... 
    } 
} 

由於PathSegment返回MultivaluedMap,同樣關鍵的是能像你的情況返回多個值(如列表)要插入到數據庫查詢多個ID。 UriInfo還提供了查詢路徑和查詢參數的MultivaluedMap

因此,您決定使用哪種參數風格,REST並不指定特定的URI設計或語義。雖然我不建議使用POST,但我建議使用GET來減少爲了向服務發送查詢所需的文檔開銷,並獲得緩存返回響應的能力。

+0

我完全同意你在說什麼。其實我相信我錯誤地誤解了地址,我的論點實際上是針對「/實體,其中......」。 –

2

做到這一點作爲每HTTP請求類型,每種請求類型應作爲每協議。

例如,HTTP/get應該總是檢索數據,並且不會使用此調用進行修改。

而且,按照REST,我們應該按如下方式使用這些HTTP類型:

  1. GET - 要檢索的實體。
  2. PUT - 要保存/更新實體
  3. POST - 要查詢或保存實體
  4. DELETE - 要刪除實體

等等......

因此,我會推薦實現一個HTTP/post類型的/查詢端點,這個端點應該是通用的,以處理最大查詢場景。

我們可以在主體中發送嵌套的json數據來指定查詢參數。

Json的身體,例如:

{ 
    "whereClause":{ 
    "OR":{ 
    { 
    "field":"name", 
    "operator":"=", 
    "value":"Raj" 
    }, 
    { 
    "field":"age", 
    "operator":">=", 
    "value":20 
    } 
    }, 
"orderByClause":{ 
"name":"ASC" 
"age":"DESC" 
}, 
"groupByClause":[ 
"name" 
] 
    } 

這樣你將實現高度的靈活性和可查詢是許多不同的方式。

希望它有幫助!

+1

謝謝,也許這就是我錯過的那種方法。 –

1

您可以創建一個帶有JSON主體的HTTP/POST請求,實體ids可以作爲數組屬性,也可以創建任何其他自定義匹配/選擇條件的其他屬性,其中將在服務上進行反序列化。

請求JSON對象:

{ 
    "entityIds" : [12,22,45,2,44,5,66], 
    "order" : "DESC" 
} 

EntityRequest.java

public class EntityRequest { 

    List<Integer> entityIds; 
    String order; 

    public List<Integer> getEntityIds() { 
     return entityIds; 
    } 

    public void setEntityIds(List<Integer> entityIds) { 
     this.entityIds = entityIds; 
    } 

    public String getOrder() { 
     return order; 
    } 

    public void setOrder(String order) { 
     this.order = order; 
    } 
} 

EntityResponse.java

public class EntityResponse 
{ 
    List<Entity> entities; 

    public List<Entity> getEntities() { 
      return entities; 
    } 
    public void setEntities(List<Entity> entities) { 
      this.entities= entities; 
    } 


} 

EntityService。java的

+0

我知道我可以做到這一點,但是我會用@POST「獲得」,這正是困擾着我的東西。 –