Primeiro
Conforme RFC 3986 §3.4 (identificadores uniformes de recursos § (componentes de sintaxe)) |
3.4 Consulta
O componente de consulta contém dados não hierárquicos que, juntamente com os dados no componente de caminho (Seção 3.3), servem para identificar um recurso dentro do escopo do esquema e da autoridade de nomenclatura do URI (se houver).
Os componentes de consulta são para recuperação de dados não hierárquicos; existem poucas coisas de natureza mais hierárquica do que uma árvore genealógica! Ergo - independentemente de você achar que é "REST-y" ou não - para estar em conformidade com os formatos, protocolos e estruturas de e para o desenvolvimento de sistemas na Internet, você não deve usar a string de consulta para identificar essas informações.
O REST não tem nada a ver com essa definição.
Antes de abordar suas perguntas específicas, seu parâmetro de consulta de "pesquisa" não recebe um nome adequado. Melhor seria tratar seu segmento de consulta como um dicionário de pares de valores-chave.
Sua string de consulta pode ser definida de maneira mais apropriada como
?first_name={firstName}&last_name={lastName}&birth_date={birthDate}
etc.
Para responder suas perguntas específicas
1) Qual design de API é mais RESTful e por quê? Semântica, eles significam e se comportam da mesma maneira. O último recurso no URI é "filhos", implicando efetivamente que o cliente está operando no recurso filho.
Eu não acho que isso seja tão claro quanto você parece acreditar.
Nenhuma dessas interfaces de recursos é RESTful. A principal pré-condição para o estilo de arquitetura RESTful é que as transições do Estado do Aplicativo devem ser comunicadas do servidor como hipermídia. As pessoas trabalharam na estrutura dos URIs para torná-los de alguma forma "URIs RESTful", mas a literatura formal sobre o REST realmente tem muito pouco a dizer sobre isso. Minha opinião pessoal é que grande parte da meta-desinformação sobre o REST foi publicada com a intenção de quebrar velhos e maus hábitos. (Construir um sistema verdadeiramente "RESTful" é, na verdade, bastante trabalhoso. A indústria procurou o "REST" e preencheu algumas preocupações ortogonais com qualificações e restrições sem sentido.)
O que a literatura do REST diz é que, se você usará o HTTP como protocolo de aplicativo, deverá seguir os requisitos formais das especificações do protocolo e não poderá "inventar o http à medida que avança e ainda declarar que está usando o http" ; Se você usar URIs para identificar seus recursos, deverá seguir os requisitos formais das especificações relacionadas a URI / URLs.
Sua pergunta é direcionada diretamente pelo RFC3986 §3.4, que vinculei acima. A linha de fundo sobre este assunto é que mesmo que um URI conforme é insuficiente para considerar uma API "RESTful", se você quiser que seu sistema realmente ser "RESTful" e você estiver usando HTTP e URIs, então você não pode identificar dados hierárquicos através do string de consulta porque:
3.4 Consulta
O componente de consulta contém dados não hierárquicos
...É simples assim.
2) Quais são os prós e os contras de cada um em termos de compreensão da perspectiva de um cliente e manutenção da perspectiva do designer.
Os "profissionais" dos dois primeiros é que eles estão no caminho certo . Os "contras" do terceiro é que parece estar completamente errado.
No que diz respeito à sua compreensibilidade e capacidade de manutenção, essas são definitivamente subjetivas e dependem do nível de compreensão do desenvolvedor do cliente e dos aspectos de design do designer. A especificação de URI é a resposta definitiva sobre como os URIs devem ser formatados. Dados hierárquicos devem ser representados no caminho e com seus parâmetros. Dados não hierárquicos devem ser representados na consulta. O fragmento é mais complicado, porque sua semântica depende especificamente do tipo de mídia da representação que está sendo solicitada. Portanto, para abordar o componente de "compreensibilidade" da sua pergunta, tentarei traduzir exatamente o que seus dois primeiros URIs estão realmente dizendo. Em seguida, tentarei representar o que você diz que está tentando realizar com URIs válidos.
Tradução dos seus URIs verbatim ao seu significado semântico
/myservice/api/v1/grandparents/{grandparentID}/parents/children?search={text}
Isto diz para os pais dos avós, que o filho deles tenha search={text}
O que você disse com o seu URI é coerente apenas se procurar pelos irmãos de um avô. Com seus "avós, pais, filhos", você encontrou um "avô" subiu uma geração com os pais e depois voltou à geração "avós" olhando para os filhos dos pais.
/myservice/api/v1/parents/{parentID}/children?search={text}
Isso indica que, para o pai identificado por {parentID}, encontre o filho dele. ?search={text}
Isso está mais próximo de corrigir o que você deseja e representa um relacionamento pai - filho que provavelmente pode ser usado para modelar toda a sua API. Para modelá-lo dessa maneira, o ônus é imputado ao cliente ao reconhecer que, se ele tiver um "grandparentId", existe uma camada de indireção entre o ID que possui e a parte do gráfico de família que deseja ver. Para encontrar um "filho" por "grandparentId", você pode ligar para o seu /parents/{parentID}/children
serviço e, em seguida, procurar um filho retornado, procurar o identificador pessoal de seus filhos.
Implementação de seus requisitos como URIs
Se você deseja modelar um identificador de recurso mais extensível que possa percorrer a árvore, posso pensar em várias maneiras de conseguir isso.
1) O primeiro, eu já aludi. Represente o gráfico de "Pessoas" como uma estrutura composta. Cada pessoa tem uma referência à geração acima dela através do caminho dos Pais e a uma geração abaixo dela através do caminho dos Filhos.
/Persons/Joe/Parents/Mother/Parents
seria uma maneira de pegar os avós maternos de Joe.
/Persons/Joe/Parents/Parents
seria uma maneira de pegar todos os avós de Joe.
/Persons/Joe/Parents/Parents?id={Joe.GrandparentID}
pegaria o avô de Joe com o identificador que você tem em mãos.
e tudo isso faria sentido (observe que pode haver uma penalidade de desempenho aqui, dependendo da tarefa, forçando um dfs no servidor devido à falta de identificação de ramificação no padrão "Pais / Pais / Pais".) Você também se beneficia de ter a capacidade de suportar qualquer número arbitrário de gerações. Se, por algum motivo, você desejar procurar 8 gerações, poderá representar isso como
/Persons/Joe/Parents/Parents/Parents/Parents/Parents/Parents/Parents/Parents?id={Joe.NotableAncestor}
mas isso leva à segunda opção dominante para representar esses dados: através de um parâmetro path.
2) Use parâmetros de caminho para "consultar a hierarquia". Você pode desenvolver a seguinte estrutura para ajudar a aliviar a carga sobre os consumidores e ainda ter uma API que faça sentido.
Olhando para trás 147 gerações, representar esse identificador de recurso com parâmetros de caminho permite que você faça
/Persons/Joe/Parents;generations=147?id={Joe.NotableAncestor}
Para localizar Joe de seu bisavô, você pode procurar no gráfico um número conhecido de gerações pela identificação de Joe.
/Persons/JoesGreatGrandparent/Children;generations=3?id={Joe.Id}
O ponto principal a ser observado nessas abordagens é que, sem mais informações no identificador e na solicitação, você deve esperar que o primeiro URI recupere uma Pessoa 147 gerações acima de Joe com o identificador de Joe.NotableAncestor. Você deve esperar que o segundo recupere Joe. Suponha que o que você realmente deseja é que o cliente que está chamando possa recuperar todo o conjunto de nós e seus relacionamentos entre a Pessoa raiz e o contexto final do seu URI. Você pode fazer isso com o mesmo URI (com alguma decoração adicional) e definindo um Accept of text/vnd.graphviz
em sua solicitação, que é o tipo de mídia registrado pela IANA para a .dot
representação gráfica. Com isso, altere o URI para
/Persons/Joe/Parents;generations=147?id={Joe.NotableAncestor.Id}#directed
com um cabeçalho de solicitação HTTP
Accept: text/vnd.graphviz
e é possível que os clientes comuniquem claramente que desejam o gráfico direcionado da hierarquia geracional entre Joe e 147 gerações anteriores, quando essa 147ª geração ancestral contiver uma pessoa identificada como "Antepassado Notável" de Joe.
Não tenho certeza se text / vnd.graphviz tem alguma semântica predefinida para seu fragmento; não encontrei nenhuma em busca de instruções. Se esse tipo de mídia realmente tiver informações de fragmentos predefinidas, sua semântica deve ser seguida para criar um URI em conformidade. Porém, se essas semânticas não forem predefinidas, a especificação do URI indicará que a semântica do identificador de fragmentos é irrestrita e, em vez disso, é definida pelo servidor, tornando esse uso válido.
3) Para que as strings de consulta são realmente usadas, além de "filtrar" seu recurso? Se você seguir a primeira abordagem, o parâmetro filter será incorporado no próprio URI como um parâmetro de caminho em vez de um parâmetro de sequência de caracteres de consulta.
Acredito que já superei isso completamente, mas as cadeias de consulta não servem para "filtrar" recursos. Eles são para identificar seu recurso a partir de dados não hierárquicos. Se você detalhou sua hierarquia com seu caminho
/person/{id}/children/
e deseja identificar um filho específico ou um conjunto específico de filhos, você usaria algum atributo que se aplica ao conjunto que está identificando e o incluiria na consulta.