Um aplicativo da Web como um cliente da API REST: como manipular identificadores de recursos


21

Vários conceitos relacionados ao REST entram em conflito na minha cabeça quando tento implementá-lo.

Eu tenho um sistema de API de back-end completo que contém a lógica de negócios e um aplicativo da web que fornece a interface do usuário. De vários recursos sobre o REST (particularmente, REST na Prática: Hipermídia e Arquitetura de Sistemas ), eu sei que não devo expor identificadores brutos de minhas entidades, mas devolver os hiperlinks com rel="self".

Considere o exemplo. A API REST possui um recurso que retorna uma pessoa:

<Person>
  <Links>
    <Link rel="self" href="http://my.rest.api/api/person/1234"/>
  </Links>
  <Pets>
    <Link rel="pet" href="http://my.rest.api/api/pet/678"/>
  </Pets>
</Person>

O problema surge com o aplicativo da web. Vamos supor que ele retorne uma página que contenha um hiperlink para os navegadores:

<body class="person">
  <p>
    <a href="http://my.web.app/pet/???????" />
  </p>
</body>

O que devo colocar no hrefatributo? Como mantenho o URL da entidade da API no aplicativo Web para poder obter a entidade quando um usuário abre a página de destino?

Os requisitos parecem conflitantes:

  1. O hiperlink hrefdeve levar ao aplicativo Web, porque é o sistema que hospeda a interface do usuário
  2. Ele hrefdeve ter algum ID da entidade porque o aplicativo Web deve poder endereçar a entidade quando a página de destino é aberta
  3. O aplicativo Web não deve analisar / construir URLs REST porque não é totalmente REST, diz o livro mencionado

URIs devem ser opacos para os consumidores. Somente o emissor do URI sabe como interpretá-lo e mapeá-lo para um recurso.

Portanto, não posso usar apenas 1234o URL de resposta da API porque, como cliente RESTful, devo tratá-lo como se fosse algo parecido http://my.rest.api/api/AGRIDd~ryPQZ^$RjEL0j. Por outro lado, devo fornecer uma URL que leve ao meu aplicativo Web e é suficiente para que o aplicativo, de alguma forma, restaure o URL original da API e use esse URL para acessar os recursos da API.

A maneira mais simples é provavelmente usar apenas os URLs da API dos recursos como identificadores de string. Mas URLs de páginas da web como http://my.web.app/person/http%3A%2F%2Fmy.rest.api%2Fapi%2Fperson%2F1234são feios.

Tudo parece bastante fácil para um aplicativo de desktop ou um aplicativo javascript de página única. Como eles vivem continuamente, eles podem simplesmente manter os URLs na memória juntamente com os objetos de serviço durante a vida útil do aplicativo e usá-los quando necessário.

Com um aplicativo da web, posso imaginar várias abordagens, mas todas parecem estranhas:

  1. Substitua o host nos URLs da API e mantenha apenas o resultado. A grande desvantagem é que ele requer que o aplicativo da Web manipule qualquer URL que a API gere, significando um acoplamento monstruoso. Além disso, não é RESTful novamente, porque meu aplicativo Web começa a interpretar os URLs.
  2. Exponha os IDs brutos na API REST junto com os links, use-os para criar URLs do Web App e, em seguida, use os IDs no servidor de aplicativos Web para encontrar os recursos necessários na API. Isso é melhor, mas afetará o desempenho do servidor de aplicativos da web porque o aplicativo da web precisará passar pela navegação do serviço REST emitindo uma cadeia de solicitações de obtenção por ID de alguma forma para lidar com qualquer solicitação de um navegador. Para um recurso um pouco aninhado, isso pode ser caro.
  3. Armazene todos os selfURLs retornados pela API em um mapeamento persistente (DB?) No servidor de aplicativos da web. Gere alguns IDs para eles, use-os para criar os URLs da página do aplicativo Web e obter os URLs dos recursos do serviço REST. Ou seja, mantenho o http://my.rest.api/pet/678URL em algum lugar com uma nova chave, digamos 3, e giro o URL da página da web como http://my.web.app/pet/3. Parece uma implementação de cache HTTP de algum tipo. Não sei por que, mas me parece estranho.

Ou isso significa que as APIs RESTful não podem servir como back-end para aplicativos da web?


1
Não está claro o que você está tentando realizar, provavelmente porque sua intenção simples está coberta sob as camadas da arquitetura que você está colocando uma sobre a outra, por isso é difícil dizer se "APIs RESTful" realmente o ajudariam. Pelo que entendi do seu problema, a opção 2 é uma solução simples e viável. O "problema" aqui é inerente às "APIs RESTful". RestIsJustSqlReinvented e você realmente enfrentará o mesmo problema ao tentar recuperar um subgrafo suficientemente complexo de qualquer RDBMS. Use um cache ou uma representação otimizada para suas consultas.
precisa saber é o seguinte

Respostas:


5

Editado para abordar atualizações de perguntas, resposta anterior removida

Examinando suas alterações na sua pergunta, acho que entendo o problema que você está enfrentando um pouco mais. Como não há um campo identificador nos seus recursos (apenas um link), você não tem como se referir a esse recurso específico na sua GUI (ou seja, um link para uma página que descreve um animal de estimação específico).

A primeira coisa a determinar é se um animal de estimação faz sentido sem um dono. Se pudermos ter um animal de estimação sem nenhum proprietário, eu diria que precisamos de algum tipo de propriedade exclusiva no animal de estimação que possamos usar para fazer referência a ele. Não acredito que isso viole a não expor o ID diretamente, pois o ID do recurso real ainda estaria escondido em um link que o cliente REST não analisaria. Com isso em mente, nosso recurso para animais de estimação pode se parecer com:

<Entity type="Pet">
    <Link rel="self" href="http://example.com/pets/1" />
    <Link rel="owner" href="http://example.com/people/1" />
    <UniqueName>Spot</UniqueName>
</Entity>

Agora, podemos atualizar o nome desse animal de estimação do Spot para o Fido sem precisar mexer com nenhum ID de recurso de fato em todo o aplicativo. Da mesma forma, podemos nos referir a esse animal de estimação em nossa GUI com algo como:

http://example.com/GUI/pets/Spot

Se o animal não faz sentido sem um proprietário (ou animais de estimação não são permitidos no sistema sem proprietário), podemos usá-lo como parte da "identidade" do animal no sistema:

http://example.com/GUI/owners/John/pets/1 (primeiro animal de estimação na lista de John)

Uma pequena observação: se ambos, animais de estimação e pessoas, existirem separados, eu não tornaria o ponto de entrada da API o recurso "Pessoas". Em vez disso, eu criaria um recurso mais genérico que conteria um link para Pessoas e animais de estimação. Pode retornar um recurso parecido com:

<Entity type="ResourceList">
    <Link rel="people" href="http://example.com/api/people" />
    <Link rel="pets" href="http://example.com/api/pets" />
</Entity>

Portanto, conhecendo apenas o primeiro ponto de entrada na API e não processando nenhum dos URLs para descobrir os identificadores do sistema, podemos fazer algo assim:

O usuário efetua login no aplicativo. O cliente REST acessa a lista inteira de recursos de pessoas disponíveis, que podem se parecer com:

<Entity type="Person">
    <Link rel="self" href="http://example.com/api/people/1" />
    <Pets>
        <Link rel="pet" href="http://example.com/api/pets/1" />
        <Link rel="pet" href="http://example.com/api/pets/2" />
    </Pets>
    <UniqueName>John</UniqueName>
</Entity>
<Entity type="Person">
    <Link rel="self" href="http://example.com/api/people/2" />
    <Pets>
        <Link rel="pet" href="http://example.com/api/pets/3" />
    </Pets>
    <UniqueName>Jane</UniqueName>
</Entity>

A GUI percorreria cada recurso e imprimiria um item da lista para cada pessoa usando o UniqueName como o "id":

<a href="http://example.com/gui/people/1">John</a>
<a href="http://example.com/gui/people/2">Jane</a>

Ao fazer isso, ele também pode processar cada link encontrado com um rel de "pet" e obter o recurso pet, como:

<Entity type="Pet">
    <Link rel="self" href="http://example.com/api/pets/1" />
    <Link rel="owner" href="http://example.com/api/people/1" />
    <UniqueName>Spot</UniqueName>
</Entity>

Com isso, ele pode imprimir um link como:

<!-- Assumes that a pet can exist without an owner -->
<a href="http://example.com/gui/pets/Spot">Spot</a>

ou

<!-- Assumes that a pet MUST have an owner -->
<a href="http://example.com/gui/people/John/pets/Spot">Spot</a>

Se seguirmos o primeiro link e assumirmos que nosso recurso de entrada possui um link com uma relação de "animais de estimação", o fluxo de controle seria algo como isto na GUI:

  1. A página é aberta e o Pet spot é solicitado.
  2. Carregue a lista de recursos do ponto de entrada da API.
  3. Carregue o recurso relacionado ao termo "animais de estimação".
  4. Examine cada recurso na resposta "animais de estimação" e encontre um que corresponda ao Spot.
  5. Exiba as informações para spot.

Usar o segundo link seria uma cadeia de eventos semelhante, com a exceção de que People é o ponto de entrada para a API e, primeiro, obteríamos uma lista de todas as pessoas no sistema, encontraríamos o que corresponderia e, em seguida, encontraríamos todos os animais de estimação pertencentes para essa pessoa (usando a tag rel novamente) e encontre a que se chama Spot, para que possamos exibir as informações específicas relacionadas a ela.


Obrigado, Mike. Atualizei minha pergunta para torná-la um pouco mais clara. O problema com sua resposta é que não posso concordar que um cliente REST possa analisar URLs. Se isso acontecer, será acoplado aos URLs. E isso viola uma das idéias principais do REST: os clientes devem usar rels para escolher os links, mas não devem assumir nenhum conhecimento da estrutura das URLs. O REST afirma que uma API é livre para alterar os URLs à vontade, desde que relpermaneçam os mesmos. A análise de URLs nos aproxima do SOAP do que do REST.
Pavel Gatilov

Mais uma vez obrigado. Você descreveu a abordagem que adotamos até agora. De certa forma, expomos identificadores. A única coisa é que tentamos expor identificadores naturais sempre que possível.
Pavel Gatilov

6

Tudo isso significa que as APIs RESTful não podem servir como back-end para aplicativos da web?

Desafio se vale a pena diferenciar entre uma API REST e um aplicativo da web. Seu "aplicação web" deve ser apenas representações alternativas (HTML) dos mesmos recursos - o que quer dizer, eu não entendo como ou por que você espera para o acesso http://my.rest.api/...e http://my.web.app/...e que sejam simultaneamente o mesmo e diferente.

Seu "cliente" é o navegador nesse caso e entende HTML e JavaScript. Essa é a aplicação web na minha opinião. Agora você pode discordar e pensar que acessa o aplicativo da Web usando foo.com e expõe tudo o mais via api.foo.com - mas é preciso perguntar: como o foo.com me forneceu a representação do recurso? O "back-end" do foo.com é perfeitamente capaz de entender como descobrir recursos no api.foo.com. Seu aplicativo da Web se tornou apenas um proxy - não é diferente do que se você estivesse falando com outra API (de outra pessoa) todos juntos.

Portanto, sua pergunta pode ser generalizada para: "Como posso descrever recursos usando meus próprios URIs que existem em outros sistemas?" o que é trivial quando você considera que não é o cliente (o HTML / JavaScript) que deve entender como fazer isso, mas o servidor. Se você concorda com o meu primeiro desafio, pode simplesmente pensar no seu aplicativo da Web como uma API REST separada que proxies ou delega para outra API REST.

Portanto, quando o cliente acessa, my.web.app/pets/1ele sabe apresentar a interface do animal de estimação, porque foi isso que foi retornado pelo modelo do servidor ou se é uma solicitação assíncrona para alguma outra representação (por exemplo, JSON ou XML), o cabeçalho do tipo de conteúdo informa isso .

O servidor que fornece isso é o responsável por entender o que é um animal de estimação e como descobrir um animal de estimação no sistema remoto. A decisão é sua: você pode simplesmente pegar o ID e gerar outro URI, que é inapropriado, ou pode ter seu próprio banco de dados que armazena o URI remoto e proxies da solicitação. Armazenar esse URI é bom - é equivalente a marcar. Você faria tudo isso apenas para ter um nome de domínio separado. Sinceramente, não sei por que você deseja isso - seus URIs da API REST também precisam ser marcados como favoritos.

Você já mencionou a maior parte disso em sua pergunta, mas acho que a estruturou de uma maneira que realmente não reconheceu que é a maneira prática de fazer o que você quer fazer (com base no que eu acho que é um restrição arbitrária - que a API e o aplicativo sejam separados). Ao perguntar se as APIs REST não podem ser back-end para aplicativos da Web e sugerir que o desempenho seria um problema, acho que você está focando tudo nas coisas erradas. É como dizer que você não pode criar um Mashup. É como dizer que a web não funciona.


Não espero que o aplicativo da Web seja simplesmente uma representação para a API. Pode haver muitas diferenças, por exemplo, mostre vários recursos filhos, juntamente com outros raiz em uma única página. Não quero que os URLs de aplicativos da web contenham os IDs internos do armazenamento de dados da API, se você quer dizer isso dizendo que espero que os dois sistemas sejam os mesmos. Não estou preocupado com o desempenho aqui, não é o problema. A pergunta é realmente 'Como faço para inserir 3 my.web.app/pets/3sem analisar os URLs da API REST'?
Pavel Gatilov 01/03

Corrigindo minha própria reformulação: 'Como faço para inserir 3 my.web.app/pets/3sem analisar o URL do recurso da API REST correspondente my.rest.api/v0/persons/2/pets/3? Ou o que eu coloco lá?
Pavel Gatilov 01/03

Eu acho que você está confundindo o estado do cliente com as representações que determinam esse estado. Você não colocar 3em app/pets/3causa app/pets/3é opaco, ele aponta para o que quer que recursos seu aplicativo web quer. Se essa é uma exibição composta de vários outros recursos (em outros sistemas - sua API é um deles), cabe a você armazenar os hiperlinks para esses sistemas no servidor de aplicativos da web e, em seguida, recuperá-los, resolvê-los para suas representações ( por exemplo, JSON ou XML) e depois servi-los como parte de sua resposta.
Doug

Pense dessa maneira - esqueça sua API e seu aplicativo. Suponha que você queira criar um site que permita às pessoas coletar suas postagens favoritas do Facebook e Twitter. Esses são sistemas remotos. Você não tentará encapsular ou modelar os URIs para esses sistemas por conta própria. Você criaria um recurso de 'placa' e seria seu servidor que sabe que board/1aponta para - facebook.com/post/123e twitter.com/status/789quando você fornece uma representação de sua placa, você teria que resolver esses URIs para uma representação com a qual possa trabalhar. Cache onde necessário.
Doug

E assim, como você deseja que sua API seja significativamente diferente do seu aplicativo (ainda acho que isso é questionável) - tratá-lo como um sistema remoto torna-se diferente. Você disse que o desempenho não é o problema, mas também disse na sua pergunta que algo assim 'afetaria o desempenho'.
Doug

5

Prefácio

Esta resposta aborda especificamente a questão de como gerenciar seu próprio esquema de URL, incluindo URLs favoritos marcáveis ​​para recursos para os quais a API REST de back-end não expõe explicitamente um identificador e sem interpretar as URLs fornecidas pela API.


A capacidade de descoberta requer uma certa quantidade de conhecimento, então aqui está minha opinião sobre um cenário do mundo real:

Digamos que queremos uma página de pesquisa na http://my.web.app/personqual os resultados incluam um link para a página de detalhes de cada pessoa. A única coisa que o nosso código front-end deve saber para fazer alguma coisa é a URL base para a sua fonte de dados REST: http://my.rest.api/api. A resposta a uma solicitação GET para este URL pode ser:

<Links>
    <Link ref="self" href="http://my.rest.api/api" />
    <Link rel="person" href="http://my.rest.api/api/person" />
    <Link rel="pet" href="http://my.rest.api/api/pet" />
</Links>

Como nossa intenção é exibir uma lista de pessoas, enviaremos uma GETsolicitação ao href a partir do personlink href, que pode retornar:

<Links>
    <Link ref="self" href="http://my.rest.api/api/person" />
    <Link rel="search" href="http://my.rest.api/api/person/search" />
</Links>

Como queremos exibir os resultados da pesquisa, usaremos o serviço de pesquisa enviando uma GETsolicitação para o searchlink href, que pode retornar:

<Persons>
    <Person>
        <Links>
            <Link rel="self" href="http://my.rest.api/api/person/1"/>
        </Links>
        <Pets>
            <Link rel="pet" href="http://my.rest.api/api/pet/10"/>
        </Pets>
    </Person>
    <Person>
        <Links>
            <Link rel="self" href="http://my.rest.api/api/person/2"/>
        </Links>
        <Pets>
            <Link rel="pet" href="http://my.rest.api/api/pet/20"/>
        </Pets>
    </Person>
</Persons>

Finalmente, temos nossos resultados, mas como criamos nossos URLs de front-end?

Vamos retirar a parte que sabemos com certeza: o URL base da API e usar o restante como nosso identificador de front-end:

  • base de API conhecida: http://my.rest.api/api
  • determinado URL para entidade individual: http://my.rest.api/api/person/1
  • ID único: /person/1
  • nosso URL base: http://my.web.app
  • nosso URL de front-end gerado: http://my.web.app/person/1

Nossos resultados podem se parecer com:

<ul>
    <li><a href="http://my.web.app/person/1">A person</a></li>
    <li><a href="http://my.web.app/person/2">A person</a></li>
</ul>

Depois que um usuário segue esse link de front-end para a página de detalhes, para qual URL enviamos a GETsolicitação de detalhes específicos person? Conhecemos nosso método para mapear URLs de back-end em URLs de front-end, portanto, apenas o invertemos:

  • URL de front-end: http://my.web.app/person/1
  • nosso URL base: http://my.web.app
  • ID único: /person/1
  • base de API conhecida: http://my.rest.api/api
  • URL da API gerado: http://my.rest.api/api/person/1

Se a API REST for alterada de forma que uma personURL esteja agora http://my.rest.api/api/different-person-base/person/1e alguém tenha marcado anteriormente http://my.web.app/person/1, a API REST deverá (pelo menos por um tempo) fornecer compatibilidade com versões anteriores, respondendo à URL antiga com um redirecionamento para a nova. Todos os links de front-end gerados incluiriam a nova estrutura automaticamente.

Como você provavelmente notou, há várias coisas que precisamos saber para navegar na API:

  • o URL base da API
  • a personrelação
  • a searchrelação

Eu não acho que haja algo errado nisso; não estamos assumindo uma estrutura de URL específica em nenhum momento; portanto, a estrutura do URL da entidade http://my.rest.api/api/person/1pode mudar e, desde que a API for compatível com versões anteriores, nosso código ainda funcionará.


Você perguntou como nossa lógica de roteamento poderia dizer a diferença entre dois URLs de front-end:

  • http://my.rest.api/api/person/1
  • http://my.rest.api/api/pet/3.

Primeiro, mostrarei que você usou a base da API no seu comentário quando, no nosso exemplo, estamos usando URLs base separados para a API da interface do usuário e da REST. Vou continuar o exemplo usando bases separadas, mas compartilhar uma base não é um problema. Podemos (ou devemos ser capazes de) mapear métodos de roteamento da interface do usuário usando o tipo de mídia do cabeçalho Accept da solicitação.

Quanto ao roteamento para uma página de detalhes específica, não podemos diferenciar esses dois URLs se formos rigorosos quanto a evitar qualquer conhecimento sobre a estrutura do selfURL fornecido pela API (ou seja, o ID da cadeia opaca). Para fazer isso funcionar, vamos incluir outra informação conhecida - o tipo de entidade com a qual estamos trabalhando - em nossos URLs de front-end.

Anteriormente, nossos URLs de front-end estavam no formato: ${UI base}/${opaque string id}

O novo formato pode ser: ${UI base}/${entity type}/${opaque string id}

Então, usando o /person/1exemplo, acabaríamos com http://my.web.app/person/person/1.

Com esse formato, nossa lógica de roteamento da interface do usuário estaria trabalhando e /person/person/1, sabendo que o primeiro token na string foi inserido por nós mesmos, podemos retirá-lo e direcioná-lo para a página de detalhes apropriada (pessoa, neste exemplo) com base nele. Se você se sentir tímido com relação a esse URL, poderemos inserir um pouco mais nele; talvez: http://my.web.app/person/detail/person/1

Nesse caso, analisaríamos o /person/detailroteamento for e usaríamos o restante como o ID da cadeia opaca.


Acho que isso introduz um acoplamento extremamente apertado do aplicativo da Web à API.

Suponho que você queira dizer que, como nosso URL de front-end gerado contém parte do URL da API, se a estrutura do URL da API mudar sem oferecer suporte à estrutura antiga, precisaremos de uma alteração de código para traduzir o URL marcado nos nova versão do URL da API. Em outras palavras, se a API REST alterar o ID de um recurso (a sequência opaca), não poderemos conversar com o servidor sobre esse recurso usando o ID antigo. Não acho que possamos evitar uma alteração de código nessa situação.

E se eu quisesse que a estrutura de URL para o aplicativo Web fosse diferente da estrutura da API?

Você pode usar qualquer estrutura de URL que desejar. No final do dia, um URL que pode ser marcado como favorito para um recurso específico deve incluir algo que você pode usar para obter um URL da API que identifique exclusivamente esse recurso. Se você gerar seu próprio identificador e armazená-lo em cache com o URL da API, como na abordagem nº 3, isso funcionará até que alguém tente usar esse URL marcado depois que a entrada for removida do cache.

E se as entidades do meu aplicativo da web não mapearem para as entidades da API 1-1?

A resposta depende do relacionamento. De qualquer forma, você precisará mapear o front-end para os URLs da API.


Eu tenho um problema com essa abordagem. Na verdade, é o número 1 na minha lista de soluções. O que eu não entendo é o seguinte: se o aplicativo web não interpreta as URLs e trata IDs exclusivos como cordas opacos (apenas person/1, pet/3), então como ele iria saber que, se um navegador é aberto http://my.rest.api/api/person/1ele deve mostrar pessoa UI, e se abre e http://my.rest.api/api/pet/3, em seguida, interface do usuário para animais de estimação?
Pavel Gatilov

Boa pergunta! Atualizei a resposta com a minha resposta.
Mike Partridge

Obrigado, Mike. Eu acho que isso introduz um acoplamento extremamente apertado do aplicativo da Web à API. E se eu quisesse que a estrutura de URLs para o aplicativo Web fosse diferente da estrutura da API? E se as entidades do meu aplicativo da web não mapearem para as entidades da API 1-1? Ainda acho que é melhor adotar a abordagem de expor alguns identificadores, mas instando os clientes a usar links para navegação.
Pavel Gatilov 28/02

Este é um tópico interessante, então espero não estar perdendo nada. Atualizei minha resposta com respostas ao seu comentário. Eu acho que expor alguns identificadores é um bom compromisso entre RESTfulness completo e usabilidade.
21813 Mike Partridge

Minha principal preocupação aqui é um pouco mais prática. Eu uso o ASP.NET MVC para implementar o aplicativo Web e, devido a algumas regras internas, tenho que definir os padrões de URL que o aplicativo suporta. Ou seja, se / a / {id} estiver definido, o aplicativo manipulará / a / 1, mas não / a / 1 / b / 2. Isso leva a um requisito de recompilar o aplicativo Web se as URLs da API REST mudarem não apenas para preservar os URLs marcados, mas também para simplesmente fazer com que o aplicativo Web funcione quando navegado a partir da raiz. Simplesmente porque os hiperlinks incorporados nas páginas html não funcionarão sem isso.
Pavel Gatilov 01/03

2

Vamos ser sinceros, não há solução mágica. Você leu Richardson Maturity Model ? Ele divide a maturidade da arquitetura REST em 3 níveis: Recursos, verbos HTTP e controles hipermídia.

Não devo expor identificadores brutos de minhas entidades, mas retornar hiperlinks com rel = "self"

Este é um controle hipermídia. Você realmente precisa? Essa abordagem tem alguns benefícios muito bons (você pode ler sobre eles aqui ). Mas não existem refeições gratuitas e você terá que trabalhar duro (por exemplo, sua segunda solução) se quiser obtê-las.

É uma questão de equilíbrio - você deseja sacrificar o desempenho (e tornar seu código mais complicado), mas obter um sistema mais flexível? Ou você prefere manter as coisas mais rápidas e simples, mas paga mais tarde quando introduz alterações no seu API / modelo?

Como alguém que desenvolveu um sistema semelhante (camada de lógica de negócios, camada da web e clientes da web), escolhi a segunda opção. Como meu grupo desenvolveu todas as camadas, decidimos que é melhor ter um pouco de acoplamento (informando a camada da web sobre os IDs das entidades e criando APIs) e, em troca, obtenha um código mais simples. A compatibilidade com versões anteriores também não foi relevante no nosso caso.

Se o aplicativo da Web foi desenvolvido por terceiros ou se a compatibilidade com versões anteriores fosse um problema, poderíamos ter escolhido de maneira diferente, pois havia um grande valor em poder alterar a estrutura da URL sem alterar o aplicativo da Web. O suficiente para justificar a complicação do código.

Tudo isso significa que as APIs RESTful não podem servir como back-end para aplicativos da web?

Eu acho que isso significa que você não precisa criar uma implementação REST perfeita. Você pode usar sua segunda solução, expor os IDs da entidade ou talvez passar APIs . Tudo bem, desde que você entenda as implicações e as compensações.


0

Eu acho que se você se ater a algo semelhante ao que Atom Syndication Formatvocê é bom.

Aqui, os metadados que descrevem a entrada que está sendo representada podem ser especificados usando elementos / atributos adicionais:

  • Conforme [RFC4287] , contém um URI que identifica exclusivamente a entrada

  • Conforme [RFC4287] , este elemento é opcional. Se incluído, ele contém o URI que um cliente deve usar para recuperar a Entrada.

Este é apenas meus dois centavos.


Talvez eu não receba algo, mas me parece que sua resposta não explica como gerar URLs de um aplicativo Web que é cliente de uma API REST, não é?
Pavel Gatilov 28/02

0

Não se preocupe com os URLs, se preocupe com os tipos de mídia.

Veja aqui (terceiro marcador em particular).

Uma API REST deve gastar quase todo o seu esforço descritivo na definição do (s) tipo (s) de mídia usado para representar recursos e direcionar o estado do aplicativo ou na definição de nomes de relações estendidos e / ou marcação ativada por hipertexto para os tipos de mídia padrão existentes. .


No caso de um aplicativo Web típico, o cliente é humano ; o navegador é apenas um agente .

Então, uma marca de âncora como

          <a href="example.com/foo/123">click here</a>

corresponde a algo como

          <link type="text/html" rel="self" href="example.com/foo/123">

A URL ainda é opaca para o usuário, tudo o que importa é com os tipos de mídia (por exemplo text/html, application/pdf, application/flv, video/x-flv, image/jpeg, image/funny-cat-picture etc). O texto descritivo contido na âncora (e no atributo title) é apenas uma maneira de estender o tipo de relacionamento de uma maneira que seja inteligível para os seres humanos.

O motivo pelo qual você deseja que o URI seja opaco para os clientes é reduzir o acoplamento (um dos principais objetivos do REST). O servidor pode alterar / reorganizar os URIs sem afetar o cliente (desde que você tenha uma boa política de armazenamento em cache - o que pode significar nenhum armazenamento em cache).

Em suma

Apenas verifique se o cliente (humano ou máquina) se importa com os tipos de mídia e as relações, e não com os URLs, e você ficará bem.


Rodrick, minha pergunta não é sobre a criação da API, mas sobre a criação de um aplicativo Web que fica no topo de uma API RESTful. Mal consigo entender como os tipos de mídia podem me ajudar a criar URLs para o aplicativo Web. Embora os tipos de mídia sejam cruciais para o contrato de serviço e a descoberta.
Pavel Gatilov 28/02

@PavelGatilov - O cliente do seu aplicativo da web é humano?
Rodrick Chapman

Sim. E muito pouco qualificado.
Pavel Gatilov

0

A maneira mais simples é provavelmente usar apenas os URLs da API dos recursos como identificadores de string. Mas URLs de páginas da web como http://my.web.app/person/http%3A%2F%2Fmy.rest.api%2Fapi%2Fperson%2F1234 são feios.

Acho que você está certo, é o caminho mais simples. Você pode relativizar os URLs http://my.rest.api/apipara torná-los menos feios:

http://my.web.app/person/person%2F1234

Se o URL fornecido pela API não for relativo a essa base, será degradado para a forma feia:

http://my.web.app/person/http%3A%2F%2Fother.api.host%2Fapi%2Fperson%2F1234

Para dar um passo adiante, inspecione a resposta do servidor da API para determinar que tipo de visualização você deseja apresentar e pare de codificar o delimitador e os dois pontos do segmento de caminho:

http://my.web.app/person/1234 (best case)
http://my.web.app/http://other.api.host/api/person/1234 (ugly case)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.