Una aplicación web como cliente API REST: cómo manejar identificadores de recursos


21

Varios conceptos relacionados con REST entran en conflicto en mi cabeza cuando intento implementarlo.

Tengo un sistema de API de fondo REST-ful que contiene la lógica empresarial y una aplicación web que proporciona la interfaz de usuario. De varios recursos sobre REST (particularmente, REST en la práctica: hipermedia y arquitectura de sistemas ) sé que no debo exponer los identificadores sin formato de mis entidades, sino más bien devolver hipervínculos con rel="self".

Considera el ejemplo. La API REST tiene un recurso que devuelve una persona:

<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>

El problema surge con la aplicación web. Supongamos que devuelve una página que contiene un hipervínculo a los navegadores:

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

¿Qué debo poner en el hrefatributo? ¿Cómo mantengo la URL de la entidad API en la aplicación web para poder obtener la entidad cuando un usuario abre la página de destino?

Los requisitos parecen contradictorios:

  1. El hipervínculo hrefdebe conducir a la aplicación web porque es el sistema que aloja la IU
  2. El hrefdebe tener algún Identificación de la entidad debido a la aplicación web debe ser capaz de hacer frente a la entidad cuando se abre la página de destino
  3. La aplicación web no debe analizar / construir URL REST porque no es REST-ful, dice el libro mencionado

Los URI deben ser opacos para los consumidores. Solo el emisor del URI sabe cómo interpretarlo y asignarlo a un recurso.

Por lo tanto, no puedo simplemente tomar 1234la URL de respuesta de la API porque, como cliente RESTful, debería tratarla como si fuera algo así http://my.rest.api/api/AGRIDd~ryPQZ^$RjEL0j. Por otro lado, debo dar alguna URL que conduzca a mi aplicación web y sea suficiente para que la aplicación de alguna manera restaure la URL original de la API y use esa URL para acceder a los recursos de la API.

Probablemente, la forma más sencilla es usar las URL de los recursos de la API como identificadores de cadena. Pero las URL de las páginas web http://my.web.app/person/http%3A%2F%2Fmy.rest.api%2Fapi%2Fperson%2F1234son feas.

Todo parece bastante fácil para una aplicación de escritorio o una aplicación de JavaScript de una sola página. Como viven continuamente, solo pueden mantener las URL en la memoria junto con los objetos de servicio durante la vida útil de la aplicación y usarlas cuando sea necesario.

Con una aplicación web puedo imaginar varios enfoques, pero todos parecen extraños:

  1. Reemplace el host en las URL de API y mantenga solo el resultado. La gran desventaja es que requiere que la aplicación web maneje cualquier URL que genere la API, lo que significa un acoplamiento monstruoso. Además, no es RESTful nuevamente, porque mi aplicación web comienza a interpretar las URL.
  2. Exponga los identificadores sin procesar en la API REST junto con los enlaces, úselos para construir las URL de la aplicación web y luego use los identificadores en el servidor de la aplicación web para encontrar los recursos necesarios en la API. Esto es mejor, pero afectará el rendimiento del servidor de la aplicación web porque la aplicación web tendrá que pasar por la navegación del servicio REST emitiendo una cadena de solicitudes get-by-id de alguna forma para manejar cualquier solicitud de un navegador. Para un recurso algo anidado, esto puede ser costoso.
  3. Almacene todas las selfURL devueltas por la API en una asignación persistente (DB?) En el servidor de aplicaciones web. Genere algunos identificadores para ellos, use los identificadores para crear las URL de la página de la aplicación web y obtener las URL de los recursos del servicio REST. Es decir, mantengo la http://my.rest.api/pet/678URL en algún lugar con una nueva clave, digamos 3, y genero la URL de la página web como http://my.web.app/pet/3. Esto parece una implementación de caché HTTP de algún tipo. No sé por qué, pero me parece extraño.

¿O significa que las API RESTful no pueden servir como backends para aplicaciones web?


1
No está claro lo que está tratando de lograr, probablemente porque su intención simple está cubierta por las capas de arquitectura que se están colocando entre sí, por lo que es difícil decir si las "API RESTful" realmente lo ayudarían. Por lo que entiendo de su problema, la opción 2 es una solución simple y viable. El "problema" aquí es inherente a las "API RESTful". RestIsJustSqlReinvented y de hecho se encontrará con el mismo problema cuando intente recuperar un subgráfico suficientemente complejo de cualquier RDBMS. Use un caché o una representación optimizada para sus consultas.
back2dos

Respuestas:


5

Editado para abordar actualizaciones de preguntas, se eliminó la respuesta anterior

Al revisar sus cambios a su pregunta, creo que entiendo el problema que enfrenta un poco más. Como no hay un campo que sea un identificador en sus recursos (solo un enlace), no tiene forma de referirse a ese recurso específico dentro de su GUI (es decir, un enlace a una página que describe una mascota específica).

Lo primero que debe determinar es si una mascota tiene sentido sin un dueño. Si podemos tener una mascota sin dueño, diría que necesitamos algún tipo de propiedad única en la mascota que podamos usar para referirnos a ella. No creo que esto violaría no exponer la ID directamente ya que la ID real del recurso aún estaría escondida en un enlace que el cliente REST no analizaría. Con eso en mente, nuestro recurso para mascotas puede verse así:

<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>

Ahora podemos actualizar el nombre de esa mascota de Spot a Fido sin tener que meterse con ninguna ID de recursos en toda la aplicación. Del mismo modo, podemos referirnos a esa mascota en nuestra GUI con algo como:

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

Si la mascota no tiene ningún sentido sin un dueño (o las mascotas no están permitidas en el sistema sin un dueño), entonces podemos usar al dueño como parte de la "identidad" de la mascota en el sistema:

http://example.com/GUI/owners/John/pets/1 (primera mascota en la lista para John)

Una pequeña nota, si tanto las mascotas como las personas pueden existir separadas entre sí, no convertiría el punto de entrada para la API en el recurso "Personas". En cambio, crearía un recurso más genérico que contendría un enlace a Personas y mascotas. Podría devolver un recurso que se parece a:

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

Entonces, al conocer solo el primer punto de entrada a la API y no procesar ninguna de las URL para descubrir los identificadores del sistema, podemos hacer algo como esto:

El usuario inicia sesión en la aplicación. El cliente REST accede a la lista completa de recursos de personas disponibles que pueden verse así:

<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>

La GUI recorrerá cada recurso e imprimirá un elemento de lista para cada persona usando UniqueName como "id":

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

Al hacer esto, también podría procesar cada enlace que encuentre con un rel de "mascota" y obtener el recurso de mascota 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>

Utilizando esto, puede imprimir un enlace como:

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

o

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

Si vamos con el primer enlace y asumimos que nuestro recurso de entrada tiene un enlace con una relación de "mascotas", el flujo de control sería algo así en la GUI:

  1. Se abre la página y se solicita el lugar para mascotas.
  2. Cargue la lista de recursos desde el punto de entrada de la API.
  3. Cargue el recurso relacionado con el término "mascotas".
  4. Mire a través de cada recurso de la respuesta "mascotas" y encuentre uno que coincida con Spot.
  5. Mostrar la información para spot.

Usar el segundo enlace sería una cadena de eventos similar, con la excepción de que People es el punto de entrada a la API y primero obtendríamos una lista de todas las personas en el sistema, encontraríamos la que coincida y luego encontraríamos todas las mascotas que pertenecen a esa persona (usando la etiqueta rel nuevamente) y encuentre la que se llama Spot para que podamos mostrar la información específica relacionada con ella.


Gracias Mike. He actualizado mi pregunta para que quede un poco más clara. El problema con su respuesta es que no puedo aceptar que un cliente REST pueda analizar URL. Si lo hace, entonces se acopla a las URL. Y esto viola una de las ideas centrales de REST: los clientes deben usar rels para elegir los enlaces, pero no deben asumir ningún conocimiento de la estructura de las URL. REST afirma que una API es libre de cambiar las URL a voluntad, siempre que relsigan siendo las mismas. Analizar las URL nos acerca más a SOAP que a REST.
Pavel Gatilov

Gracias de nuevo. Has descrito el enfoque que hemos tomado hasta ahora. En cierto modo, exponemos identificadores. Lo único es que tratamos de exponer identificadores naturales siempre que sea posible.
Pavel Gatilov

6

¿Significa todo esto que las API RESTful no pueden servir como backends para aplicaciones web?

Desafío si vale la pena diferenciar entre una API REST y una aplicación web. Su "aplicación web" debe ser sólo representaciones alternativas (HTML) de los mismos recursos - que equivale a decir, que no entiendo cómo o por qué se puede esperar para el acceso http://my.rest.api/...y http://my.web.app/..., y que sean al mismo tiempo iguales y diferentes.

Su "cliente" es el navegador en este caso y entiende HTML y JavaScript. Esa es la aplicación web en mi opinión. Ahora puede estar en desacuerdo y pensar que accede a dicha aplicación web usando foo.com y expone todo lo demás a través de api.foo.com, pero luego debe preguntar, ¿cómo me proporcionó foo.com la representación del recurso? El "back-end" de foo.com es perfectamente capaz de comprender cómo descubrir recursos de api.foo.com. Su aplicación web se ha convertido simplemente en un proxy, no diferente de si estuviera hablando con otra API (de otra persona) todos juntos.

Por lo tanto, su pregunta se puede generalizar a "¿Cómo puedo describir los recursos utilizando mis propios URI que existen en otros sistemas?" lo cual es trivial cuando considera que no es el cliente (el HTML / JavaScript) el que debe entender cómo hacer esto, sino el servidor. Si está de acuerdo con mi primer desafío, simplemente puede pensar en su aplicación web como una API REST separada que representa o delega a otra API REST.

Entonces, cuando su cliente accede my.web.app/pets/1, sabe que debe presentar la interfaz de mascota porque eso es lo que devolvió la plantilla del lado del servidor, o si se trata de una solicitud asincrónica de alguna otra representación (por ejemplo, JSON o XML), el encabezado de tipo de contenido lo indica .

El servidor que proporciona esto es el responsable de comprender qué es una mascota y cómo descubrirla en el sistema remoto. La forma de hacerlo depende de usted: puede simplemente tomar la ID y generar otro URI, que es lo que considera inapropiado, o puede tener su propia base de datos que almacena el URI remoto y representa la solicitud. Almacenar este URI está bien, es equivalente a marcar como favorito. Harías todo esto solo para tener un nombre de dominio separado. Sinceramente, no sé por qué quieres esto: tus URI de API REST también deben poder agregar marcadores.

Ya ha mencionado la mayor parte de esto en su pregunta, pero siento que lo ha enmarcado de una manera que realmente no reconoce que es la forma práctica de hacer lo que quiere hacer (en base a lo que siento es un restricción arbitraria: que la API y la aplicación estén separadas). Al preguntar si las API REST no pueden ser back-end para aplicaciones web y sugerir que el rendimiento sería un problema, creo que te estás centrando en las cosas incorrectas. Es como decir que no puedes crear un Mashup. Es como decir que la web no funciona.


No espero que la aplicación web sea simplemente una representación de la API. Puede tener muchas diferencias, por ejemplo, mostrar varios recursos secundarios junto con alguno raíz en una sola página. No quiero que las URL de la aplicación web contengan los identificadores internos del almacenamiento de datos de la API, si quiere decir esto al decir que espero que los 2 sistemas sean iguales. No me preocupa el rendimiento aquí, no es el problema. La pregunta es en realidad '¿Cómo pongo 3 my.web.app/pets/3sin analizar las URL de REST API'?
Pavel Gatilov

Corrigiendo mi propia reformulación: '¿Cómo pongo 3 my.web.app/pets/3sin analizar la URL del recurso REST API correspondiente my.rest.api/v0/persons/2/pets/3? ¿O qué pongo allí?
Pavel Gatilov

Creo que estás confundiendo el estado del cliente con las representaciones que determinan ese estado. Usted no pone 3en app/pets/3porque app/pets/3es opaca, lo que apunta a los recursos de su aplicación web quiere. Si esa es una vista compuesta de varios otros recursos (en otros sistemas, su API es uno de ellos), entonces depende de usted almacenar los hipervínculos a esos sistemas dentro del servidor de aplicaciones web, y luego recuperarlos, resolverlos en sus representaciones ( JSON o XML) y luego servirlos como parte de su respuesta.
Doug

Piénselo de esta manera: olvide su API y aplicación. Suponga que desea crear un sitio que permita a las personas recopilar sus publicaciones favoritas de Facebook y Twitter. Esos son sistemas remotos. No va a tratar de hacer un túnel o moldear los URI a esos sistemas a través del suyo. Crearía un recurso de 'tablero' y sería su servidor el que sabe lo que board/1apunta facebook.com/post/123y twitter.com/status/789, cuando vaya a proporcionar una representación de su tablero, tendrá que resolver esos URI a una representación con la que pueda trabajar. Caché donde sea necesario.
Doug

Y así, dado que desea que su API sea significativamente diferente de su aplicación (todavía creo que esto es cuestionable), tratarlo como un sistema remoto no se diferencia de eso. Dijiste que el rendimiento no es el problema, pero también dijiste en tu pregunta que algo como esto 'afectaría el rendimiento'.
Doug

5

Prefacio

Esta respuesta aborda específicamente la cuestión de cómo administrar su propio esquema de URL, incluidas las URL únicas que se pueden marcar para recursos para los cuales la API REST de fondo no expone explícitamente un identificador, y sin interpretar las URL proporcionadas por la API.


La capacidad de descubrimiento requiere una cierta cantidad de conocimiento, así que aquí está mi opinión sobre un escenario del mundo real:

Digamos que queremos una página de búsqueda en la http://my.web.app/personque los resultados incluyan un enlace a la página de detalles para cada persona. La única cosa que nuestro código de aplicaciones para usuario debe conocer a fin de hacer nada en absoluto es la URL base de su fuente de datos REST: http://my.rest.api/api. La respuesta a una solicitud GET a esta URL podría 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 nuestra intención es mostrar una lista de personas, a continuación enviamos una GETsolicitud a href desde el personenlace href, que podría devolver:

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

Queremos mostrar los resultados de búsqueda, por lo que utilizaremos el servicio de búsqueda enviando una GETsolicitud al searchenlace href, que podría devolver:

<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 tenemos nuestros resultados, pero ¿cómo construimos nuestras URL front-end?

Eliminemos la parte que conocemos con certeza: la URL base de la API, y usemos el resto como nuestro identificador front-end:

  • base API conocida: http://my.rest.api/api
  • URL dada para entidad individual: http://my.rest.api/api/person/1
  • Identificación única: /person/1
  • nuestra URL base: http://my.web.app
  • nuestra URL front-end generada: http://my.web.app/person/1

Nuestros resultados pueden verse así:

<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>

Una vez que un usuario sigue ese enlace frontal a la página de detalles, ¿a qué URL enviamos la GETsolicitud de detalles específicos person? Conocemos nuestro método para mapear las URL de back-end en las URL de front-end, por lo que simplemente lo revertimos:

  • URL front-end: http://my.web.app/person/1
  • nuestra URL base: http://my.web.app
  • Identificación única: /person/1
  • base API conocida: http://my.rest.api/api
  • URL de API generada: http://my.rest.api/api/person/1

Si la API REST cambia de manera tal que personahora hay una URL http://my.rest.api/api/different-person-base/person/1y alguien había marcado previamente http://my.web.app/person/1, la API REST debería (al menos por un tiempo) proporcionar compatibilidad con versiones anteriores respondiendo a la URL anterior con una redirección a la nueva. Todos los enlaces front-end generados incluirían la nueva estructura automáticamente.

Como probablemente haya notado, hay varias cosas que debemos saber para navegar por la API:

  • la URL base de la API
  • la personrelacion
  • la searchrelacion

No creo que haya nada malo en esto; no estamos asumiendo una estructura de URL específica en ningún momento, por lo que la estructura de la URL de la entidad http://my.rest.api/api/person/1podría cambiar, y mientras la API proporcione compatibilidad con versiones anteriores, nuestro código seguirá funcionando.


Preguntó cómo nuestra lógica de enrutamiento podría diferenciar entre dos URL de front-end:

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

Primero, señalaré que usó la base API en su comentario cuando, en nuestro ejemplo, usamos URL base separadas para la UI y la API REST. Continuaré el ejemplo usando bases separadas, pero compartir una base no es un problema. Podemos (o deberíamos poder) asignar métodos de enrutamiento de IU utilizando el tipo de medio del encabezado Aceptar de la solicitud.

En cuanto al enrutamiento a una página de detalles específica, no podemos diferenciar esas dos URL si somos estrictos para evitar cualquier conocimiento sobre la estructura de la selfURL proporcionada por la API (es decir, la identificación de cadena opaca). Para que esto funcione, incluyamos otra de nuestras piezas de información conocidas, el tipo de entidad con el que estamos trabajando, en nuestras URL de front-end.

Anteriormente, nuestras URL de front-end tenían el formato: ${UI base}/${opaque string id}

El nuevo formato podría ser: ${UI base}/${entity type}/${opaque string id}

Entonces, usando el /person/1ejemplo, terminaríamos con http://my.web.app/person/person/1.

Con este formato, nuestra lógica de enrutamiento de la interfaz de usuario funcionaría /person/person/1, y sabiendo que nosotros insertamos el primer token en la cadena, podemos extraerlo y enrutarlo a la página de detalles apropiada (persona, en este ejemplo) en función de él. Si se siente avergonzado acerca de esa URL, podríamos insertar un poco más allí; tal vez: http://my.web.app/person/detail/person/1

En cuyo caso, analizaríamos el /person/detailenrutamiento y usaremos el resto como la identificación de cadena opaca.


Creo que esto introduce un acoplamiento extremadamente estrecho de la aplicación web a la API.

Supongo que quiere decir que, dado que nuestra URL front-end generada contiene parte de la URL de la API, si la estructura de la URL de la API cambia sin admitir la estructura anterior, necesitaremos un cambio de código para traducir la URL marcada al marcador nueva versión de la URL de la API. En otras palabras, si la API REST cambia la ID de un recurso (la cadena opaca), entonces no podemos hablar con el servidor sobre ese recurso usando la ID anterior. No creo que podamos evitar un cambio de código en esa situación.

¿Qué sucede si quisiera que la estructura de URL para la aplicación web difiera de la de la API?

Puede usar cualquier estructura de URL que desee. Al final del día, una URL marcable para un recurso específico debe incluir algo que pueda usar para obtener una URL de API que identifique ese recurso de manera única. Si genera su propio identificador y lo almacena en caché con la URL de API como en su enfoque # 3, eso funcionará hasta que alguien intente usar esa URL marcada después de que esa entrada se borre de la caché.

¿Qué sucede si las entidades de mi aplicación web no se asignaron a las entidades de la API 1-1?

La respuesta depende de la relación. De cualquier manera, necesitaría una forma de asignar el front-end a las URL de API.


Tengo un problema con este enfoque. De hecho, es el número 1 en mi lista de soluciones. Lo que no entiendo es la siguiente: si la aplicación web no interpreta las direcciones URL y golosinas identificadores únicos como cadenas opacos (sólo person/1, pet/3), entonces ¿cómo podría saber que si un navegador abre http://my.rest.api/api/person/1debe mostrar persona de interfaz de usuario, y si se abre http://my.rest.api/api/pet/3, luego la interfaz de usuario de la mascota?
Pavel Gatilov

¡Buena pregunta! He actualizado la respuesta con mi respuesta.
Mike Partridge

Gracias Mike. Creo que esto introduce un acoplamiento extremadamente estrecho de la aplicación web a la API. ¿Qué sucede si quisiera que la estructura de URL para la aplicación web difiera de la de la API? ¿Qué sucede si las entidades de mi aplicación web no se asignaron a las entidades de la API 1-1? Todavía creo que sería mejor adoptar el enfoque de exponer algunos identificadores, pero instando a los clientes a usar enlaces para la navegación.
Pavel Gatilov

Este es un tema interesante, así que espero no perderme nada. He actualizado mi respuesta con respuestas a tu comentario. Creo que exponer algunos identificadores es un buen compromiso entre RESTfulness completo y usabilidad.
Mike Partridge

Mi principal preocupación aquí es un poco más práctica. Utilizo ASP.NET MVC para implementar la aplicación web y, debido a algunas reglas internas, tengo que definir patrones de URL compatibles con la aplicación. Es decir, si se define / a / {id}, la aplicación manejará / a / 1, pero no / a / 1 / b / 2. Esto lleva a un requisito de recompilar la aplicación web si las URL de la API REST cambian no solo para preservar las URL marcadas, sino también para hacer que la aplicación web funcione cuando se navega desde la raíz. Simplemente porque los hipervínculos incrustados en páginas html no funcionarán sin eso.
Pavel Gatilov

2

Seamos realistas, no hay una solución mágica. ¿Has leído el modelo de madurez de Richardson ? Divide la madurez de la arquitectura REST en 3 niveles: recursos, verbos HTTP y controles hipermedia.

No debería exponer los identificadores sin formato de mis entidades, sino devolver hipervínculos con rel = "self"

Esto es controles hipermedia. ¿Realmente lo necesitas? Este enfoque tiene algunos beneficios muy buenos (puede leer sobre ellos aquí ). Pero no hay comidas gratuitas y tendrá que trabajar duro (por ejemplo, su segunda solución) si desea obtenerlas.

Es una cuestión de equilibrio: ¿desea sacrificar el rendimiento (y hacer que su código sea más complicado) pero obtener un sistema que sea más flexible? ¿O prefiere mantener las cosas más rápidas y simples pero pagar después cuando introduce cambios en su api / modelo?

Como alguien que desarrolló un sistema similar (nivel de lógica empresarial, nivel web y clientes web) elegí la segunda opción. Dado que mi grupo desarrolló todos los niveles, decidimos que es mejor tener un poco de acoplamiento (al permitir que el nivel web conozca los identificadores de entidad y la creación de api urls) y, a cambio, obtenga un código que sea más simple. La compatibilidad con versiones anteriores tampoco era relevante en nuestro caso.

Si la aplicación web fue desarrollada por un tercero o si la compatibilidad con versiones anteriores era un problema, podríamos haber elegido de manera diferente porque entonces era muy valioso poder cambiar la estructura de la URL sin cambiar la aplicación web. Suficiente para justificar la complicación del código.

¿Significa todo esto que las API RESTful no pueden servir como backends para aplicaciones web?

Creo que significa que no tiene que crear una implementación REST perfecta. Puede ir con su segunda solución, o exponer los identificadores de la entidad o tal vez pasar api urls . Está bien, siempre y cuando comprenda las implicaciones y las compensaciones.


0

Creo que si te apegas a algo similar a lo Atom Syndication Formatque eres bueno.

Aquí, los metadatos que describen la entrada que se representa se pueden especificar utilizando elementos / atributos adicionales:

  • Según [RFC4287] , contiene un URI que identifica de forma exclusiva la entrada

  • Según [RFC4287] , este elemento es opcional. Si se incluye, contiene el URI que un cliente debe usar para recuperar la Entrada.

Estos son mis únicos dos centavos.


Tal vez no obtengo algo, pero me parece que su respuesta no explica cómo generar URL de una aplicación web que es cliente de una API REST, ¿verdad?
Pavel Gatilov

0

No te preocupes por las URL, preocúpate por los tipos de medios.

Ver aquí (tercer punto en particular).

Una API REST debería dedicar casi todo su esfuerzo descriptivo a definir los tipos de medios utilizados para representar los recursos y dirigir el estado de la aplicación, o para definir nombres de relaciones extendidas y / o marcado habilitado para hipertexto para los tipos de medios estándar existentes. .


En el caso de una aplicación web típica, el cliente es un humano ; El navegador es solo un agente .

Entonces una etiqueta de anclaje 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">

La URL todavía es opaca para el usuario, lo único que le importa son los tipos de medios (por ejemplo text/html, application/pdf, application/flv, video/x-flv, image/jpeg, image/funny-cat-picture etc). El texto descriptivo contenido en el ancla (y en el atributo de título) es solo una forma de extender el tipo de relación de una manera que sea inteligible para los humanos.

La razón por la que desea que el URI sea opaco para los clientes es para reducir el acoplamiento (uno de los objetivos principales de REST). El servidor puede cambiar / reorganizar los URI sin afectar al cliente (siempre que tenga una buena política de almacenamiento en caché, lo que puede significar que no haya almacenamiento en caché).

En resumen

Solo asegúrese de que el cliente (humano o máquina) se preocupe por los tipos de medios y las relaciones en lugar de las URL y estará bien.


Rodrick, mi pregunta no se trata de crear la API, sino de crear una aplicación web que se encuentre encima de una API RESTful. Apenas puedo entender cómo los tipos de medios pueden ayudarme a crear URL para la aplicación web. Aunque los tipos de medios son cruciales para el contrato de servicio y la capacidad de descubrimiento.
Pavel Gatilov

@PavelGatilov - ¿Es humano el cliente de su aplicación web?
Rodrick Chapman

Sí lo es. Y uno muy poco calificado.
Pavel Gatilov

0

Probablemente, la forma más sencilla es usar las URL de los recursos de la API como identificadores de cadena. Pero las URL de páginas web como http://my.web.app/person/http%3A%2F%2Fmy.rest.api%2Fapi%2Fperson%2F1234 son feas.

Creo que tienes razón, esa es la forma más simple. Puedes relativizar las URL http://my.rest.api/apipara que sean menos feas:

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

Si la URL proporcionada por la API no es relativa a esa base, se degrada a la forma fea:

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

Para ir un paso más allá, inspeccione la respuesta del servidor API para determinar qué tipo de vista desea presentar y deje de codificar el delimitador de segmento de ruta y los dos puntos:

http://my.web.app/person/1234 (best case)
http://my.web.app/http://other.api.host/api/person/1234 (ugly case)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.