Quando usar recursos aninhados em uma API RESTful

16

Eu tenho dois recursos: usuários e links.

Os usuários podem ter vários links associados a eles. Eu projetei minha API RESTful para que você possa acessar os links associados a um usuário no seguinte URI:

/users/:id/links

No entanto, eu sempre preciso ter um URI apenas para links - às vezes eu posso querer todos os links, independentemente do usuário.

Para isso eu tenho:

/links

Isso soa bem? Tendo dois URIs para links?

Gostaria de saber se eu deveria acessar os links para um usuário com um URI, como:

/links/user/:id ou /links/?user=:id

Dessa forma, eu tenho apenas um recurso para links.

Oliver Joseph Ash
fonte
3
hmm .. Este parece ser mais elegante:/links/user/:id
theMarceloR 18/02
7
@ theMarceloR: Esse é o único exemplo dos três que não acho particularmente claro. O recurso é para um link ou usuário? O URI é muito menos ambíguo usando o método de recurso aninhado ( /users/:id/links) ou o método de cadeia de caracteres de consulta ( /links/?user=:id), pois na verdade é uma consulta. /links/user/:idpode parecer bom e / ou ser mais fácil de rotear em algumas estruturas, mas na verdade é bastante confuso.
Aaronaught

Respostas:

16

Não, não há nada errado em ter vários recursos para a mesma "coisa", neste caso, listas de links.

Recentemente, estávamos lutando com o mesmo problema. Nossa decisão foi ter todos os recursos onde não há uma propriedade estrita a não ser aninhada. Em outras palavras, os links seriam modelados sob

/links -- all links
/links/:linkid -- a particular link

Em seguida, os filtros na coleção de links são expressos como parâmetros de consulta. Portanto, para obter os links de um determinado usuário, você usaria:

/links?user=/users/:userid

Isso também permite uma composição mais fácil dos filtros:

/links?user=/users/10&since=2013-01-01

E é fácil entender conceitualmente - você tem uma coleção de itens e adiciona filtros a ela.

Dito isto, não há nada mais "RESTful" nessa abordagem do que qualquer outro esquema de nomeação de URI. É apenas uma convenção que achamos legível por humanos e fácil para nós, desenvolvedores, entender e abraçar. O REST não se importa com o que você coloca em seus identificadores de recursos.

waxwing
fonte
1
"Todos os recursos em que não existe uma propriedade estrita a não ser aninhada" parecem uma boa regra. Muitíssimo obrigado.
Oliver Joseph Ash
5
Eu diria que não é algo de errado em ter vários recursos para a mesma entidade física, mas isso não é realmente o que é isso. Cada link individual possui uma URL canônica (links /: id), enquanto que cada um dos recursos acima é de fato um único recurso (/ links) com filtros aplicados. Além disso, estou perplexo com o ?user=users/:useridna cadeia de consulta; o que há de errado com apenas ?userid=:userid?
Aaronaught
2
@Aaronaught: o motivo de se manter nos uri em vez de nos IDs simples é para que os clientes possam tratar todos os identificadores de recursos da mesma forma, ou seja, um cliente precisa saber apenas que 'esse usuário é identificado por "/*******"; Onde os *são opacos. mas esse mesmo identificador sempre pode ser usado para se referir a esse recurso (como em, com links), para buscar a versão mais atual desse recurso e assim por diante. o conteúdo desse uri é entendido apenas pelo servidor de origem. Isso também significa que, se os identificadores precisam mudar, digamos /realm/:businessid/users/:id, o cliente não muda.
SingleNegationElimination
@TokenMacGuy: Desculpe, não entendo nenhuma parte do seu comentário. Qual é a diferença prática entre /users/:userid/linkse /links?userid=:userid? Nos dois casos, os identificadores não mudam, eles buscam a versão atual desse recurso e o cliente os trata da mesma maneira. Não existe um URL canônico para isso, porque não é um recurso, é uma consulta; portanto, esses são apenas dois tipos diferentes de sintaxe de consulta. Também não estou claro como o cliente não precisaria mudar se a estrutura da URL mudar; isso é considerado uma mudança de quebra no REST, a menos que um 301 esteja em vigor.
Aaronaught 19/10/2013
1
@Aaronaught: Eu posso ter entendido mal a sua preocupação. Suponha que ele /linkssuporte uma interface de consulta, /links?user=/users/123permita uma abordagem de caixa preta para identificadores de recursos em clientes que /links?userid=123não. o último requer que o cliente entenda o que é um ID do usuário e como obtê-lo, presumivelmente fora do recurso obtido de /users/123ou /links/456/user. O primeiro significa que o cliente pode usar o uri sem modificação; supondo que o /links/.../userfornece uma resposta hipermídia (digamos, com Location:cabeçalhos).
SingleNegationElimination
1

Portanto, minha preocupação é: / users /: userid / links retorna "links", MAS se o user_id não for identificado, isso deve retornar um 404.

Contudo

/ links? userid =: userid retornaria uma lista vazia (essencialmente 200) que provavelmente é um bug. E bem possível.

Embora ambos funcionem, o aninhamento fornece funcionalidade adicional, que você pode usar posteriormente.

Richard Browne
fonte