Comprensión de RPC frente a REST para API HTTP

 

 

 

  • Accesibilidad para diseñadores, con Stéphanie Walter
  • SmashingConf Friburgo 2024

  • Índice
    1. ¿Para qué son?
    2. Cuando las acciones no pueden ser pensamientos posteriores
    3. Utilice REST y RPC
      1. Otras lecturas

    REST significa "transferencia de estado representacional". Durante los últimos años, cada vez que alguien quiere comenzar a crear una API HTTP, utiliza prácticamente exclusivamente REST como estilo arquitectónico de referencia, en lugar de enfoques alternativos como XML-RPC, SOAP y JSON-RPC. En este artículo, Phil Sturgeon analiza dos enfoques en el contexto de la creación de API HTTP. Tanto RPC como REST se pueden utilizar a través de otros protocolos de transporte, como AMQP, pero ese es otro tema completamente diferente.

     

    Conocer las diferencias entre REST y RPC puede resultar increíblemente útil cuando planifica una nueva API y puede ser de gran ayuda cuando trabaja en funciones para API existentes. Es mejor no mezclar estilos en una sola API, porque esto podría resultar confuso tanto para los consumidores de su API como para cualquier herramienta que espera un conjunto de convenciones (REST, por ejemplo) y que falla cuando ve una diferente. conjunto de convenciones (RPC). Utilice REST cuando tenga sentido o utilice RPC si es más apropiado. ¡O usa ambos y disfruta de lo mejor de ambos mundos!

    Durante los últimos años, cada vez que alguien quiere comenzar a construir una API HTTP, utiliza prácticamente exclusivamente REST como estilo arquitectónico de referencia, en lugar de enfoques alternativos como XML-RPC, SOAP y JSON-RPC. Muchos consideran que REST es, en última instancia, superior a los otros enfoques "basados ​​en RPC", lo cual es un poco engañoso porque simplemente son diferentes.

    Este artículo analiza estos dos enfoques en el contexto de la creación de API HTTP , porque así es como se usan con mayor frecuencia. Tanto RPC como REST se pueden utilizar a través de otros protocolos de transporte, como AMQP, pero ese es otro tema completamente diferente.

    REST significa " transferencia de estado representacional " , descrita por Roy Fielding en su disertación . Lamentablemente, esa disertación no es muy leída y muchas personas tienen su propia idea de qué es REST, lo que genera mucha confusión y desacuerdo. REST tiene que ver con una relación cliente-servidor, donde los datos del lado del servidor están disponibles a través de representaciones de datos en formatos simples, a menudo JSON y XML. Estas representaciones de recursos, o colecciones de recursos, que luego son potencialmente modificables, y las acciones y relaciones se hacen detectables a través de un método conocido como hipermedia. Hipermedia es fundamental para REST y es esencialmente solo el concepto de proporcionar enlaces a otros recursos.

     

    Más allá de los hipermedia, existen algunas otras limitaciones, como por ejemplo:

    • REST debe ser sin estado: no persistir sesiones entre solicitudes.
    • Las respuestas deben declarar capacidad de almacenamiento en caché: ayuda a que su API escale si los clientes respetan las reglas.
    • REST se centra en la uniformidad: si utiliza HTTP, debe utilizar funciones HTTP siempre que sea posible, en lugar de inventar convenciones.

    Estas restricciones (y algunas más ) permiten que la arquitectura REST ayude a que las API duren décadas, no solo años.

    Antes de que REST se hiciera popular (después de que empresas como Twitter y Facebook etiquetaran sus API como REST), la mayoría de las API se creaban utilizando XML-RPC o SOAP. XML-RPC fue problemático porque es difícil garantizar los tipos de datos de las cargas útiles XML. En XML, muchas cosas son solo cadenas, por lo que es necesario superponer metadatos para describir cosas como qué campos corresponden a qué tipos de datos. Esto se convirtió en parte de la base de SOAP (Protocolo simple de acceso a objetos). XML-RPC y SOAP, junto con soluciones locales personalizadas, dominaron el panorama de API durante mucho tiempo y eran todas API HTTP basadas en RPC.

    La parte "RPC" significa "llamada a procedimiento remoto" y es esencialmente lo mismo que llamar a una función en JavaScript, PHP, Python, etc., tomando un nombre de método y argumentos. Dado que XML no es del agrado de todos, una API RPC podría usar el protocolo JSON-RPC , o podría implementar una API personalizada basada en JSON, como lo ha hecho Slack con su API web .

    Tome este ejemplo de llamada RPC:

    POST /sayHello HTTP/1.1HOST: api.example.comContent-Type: application/json{"name": "Racey McRacerson"}

    En JavaScript, haríamos lo mismo definiendo una función y luego la llamaríamos en otro lugar:

    /* Signature */function sayHello(name) { // ...}/* Usage */sayHello("Racey McRacerson");

    La idea es la misma. Una API se construye definiendo métodos públicos; luego, los métodos se llaman con argumentos. RPC es solo un conjunto de funciones, pero en el contexto de una API HTTP, eso implica colocar el método en la URL y los argumentos en la cadena o cuerpo de la consulta. SOAP puede ser increíblemente detallado para acceder a datos similares pero diferentes, como informes. Si busca "ejemplo SOAP" en Google, encontrará un ejemplo de Google que demuestra un método llamado getAdUnitsByStatement, que se ve así:

    ?xml version="1.0" encoding="UTF-8"?soapenv:Envelope xmlns_soapenv="https://schemas.xmlsoap.org/soap/envelope/" xmlns_xsd="https://www.w3.org/2001/XMLSchema" xmlns_xsi="https://www.w3.org/2001/XMLSchema-instance" soapenv:Header ns1:RequestHeader soapenv_actor="https://schemas.xmlsoap.org/soap/actor/next" soapenv_mustUnderstand="0" xmlns_ns1="https://www.google.com/apis/ads/publisher/v201605" ns1:networkCode123456/ns1:networkCode ns1:applicationNameDfpApi-Java-2.1.0-dfp_test/ns1:applicationName /ns1:RequestHeader /soapenv:Header soapenv:Body getAdUnitsByStatement filterStatement queryWHERE parentId IS NULL LIMIT 500/query /filterStatement /getAdUnitsByStatement /soapenv:Body/soapenv:Envelope

    Esta es una carga útil enorme, todo ahí simplemente para envolver este argumento:

     

    queryWHERE parentId IS NULL LIMIT 500/query

    En JavaScript, se vería así:

    /* Signature */function getAdUnitsByStatement(filterStatement) { // ...};/* Usage */getAdUnitsByStatement('WHERE parentId IS NULL LIMIT 500');

    En una API JSON más simple, podría verse más parecido a esto:

    POST /getAdUnitsByStatement HTTP/1.1HOST: api.example.comContent-Type: application/json{"filter": "WHERE parentId IS NULL LIMIT 500"}

    Aunque esta carga útil es mucho más sencilla, todavía necesitamos tener métodos diferentes para getAdUnitsByStatementy getAdUnitsBySomethingElse. REST muy rápidamente comienza a verse "mejor" cuando se observan ejemplos como este, porque permite combinar puntos finales genéricos con elementos de cadena de consulta (por ejemplo, GET /ads?statement={foo}o GET /ads?something={bar}). Puede combinar elementos de cadena de consulta para obtener GET /ads?statement={foo}amp;limit=500y pronto deshacerse de esa extraña sintaxis de estilo SQL que se envía como argumento.

    Hasta ahora, REST parece superior, pero solo porque estos ejemplos utilizan RPC para algo que REST es más hábil en manejar. Este artículo no intentará describir cuál es “mejor”, sino que le ayudará a tomar una decisión informada sobre cuándo un enfoque podría ser más apropiado.

    ¿Para qué son?

    Las API basadas en RPC son excelentes para acciones (es decir, procedimientos o comandos).

    Las API basadas en REST son excelentes para modelar su dominio (es decir, recursos o entidades), haciendo que CRUD (crear, leer, actualizar, eliminar) esté disponible para todos sus datos.

    REST no es solo CRUD, sino que las cosas se hacen principalmente a través de operaciones basadas en CRUD. REST utilizará métodos HTTP como GET, POST, PUT, y, con suerte, DELETEpara proporcionar un significado semántico a la intención de la acción que se está realizando.OPTIONSPATCH

    RPC, sin embargo, no haría eso. La mayoría usa solo GETy POST, y GETse usa para buscar información y POSTpara todo lo demás. Es común ver que las API de RPC usan algo como POST /deleteFoo, con un cuerpo de { "id": 1 }, en lugar del enfoque REST, que sería DELETE /foos/1.

    Esta no es una diferencia importante; es simplemente un detalle de implementación. En mi opinión, la mayor diferencia está en cómo se manejan las acciones. En RPC, solo tienes POST /doWhateverThingNowy eso está bastante claro. Pero con REST, usar estas operaciones tipo CRUD puede hacerte sentir que REST no sirve para manejar nada más que CRUD. Tramites en Ecuador

     

    Bueno, ese no es del todo el caso. Las acciones desencadenantes se pueden realizar con cualquiera de los dos enfoques; pero, en DESCANSO, ese desencadenante puede considerarse más como un efecto secundario. Por ejemplo, si desea "Enviar un mensaje" a un usuario, RPC sería este:

    POST /SendUserMessage HTTP/1.1Host: api.example.comContent-Type: application/json{"userId": 501, "message": "Hello!"}

    Pero en REST, la misma acción sería esta:

    POST /users/501/messages HTTP/1.1Host: api.example.comContent-Type: application/json{"message": "Hello!"}

    Aquí hay una gran diferencia conceptual, incluso si parecen bastante similares:

    • RPC .
      Estamos enviando un mensaje y eso podría terminar almacenando algo en la base de datos para mantener un historial, que podría ser otra llamada RPC con posiblemente los mismos nombres de campo, ¿quién sabe?
    • DESCANSAR .
      Estamos creando un recurso de mensajes en la colección de mensajes del usuario. Podemos ver un historial de estos fácilmente haciendo un clic GETen la misma URL y el mensaje se enviará en segundo plano.

    Esta "acciones suceden como una ocurrencia tardía" se puede utilizar en REST para encargarse de muchas cosas. Imagine una aplicación de viajes compartidos que tenga "viajes". Esos viajes deben tener acciones de "inicio", "finalización" y "cancelación", de lo contrario el usuario nunca sabría cuándo comenzaron o terminaron.

    En una API REST, ya tienes GET /tripsy POST /trips, por lo que mucha gente intentaría usar puntos finales que se parecen un poco a subrecursos para estas acciones:

    • POST /trips/123/start
    • POST /trips/123/finish
    • POST /trips/123/cancel

    Básicamente, esto consiste en bloquear puntos finales de estilo RPC en una API REST, que sin duda es una solución popular pero técnicamente no es REST. Este cruce es una señal de lo difícil que puede ser poner acciones en DESCANSO. Aunque al principio no resulte obvio, es posible. Un enfoque es utilizar una máquina de estados, en algo así como un statuscampo:

    PATCH /trips/123 HTTP/1.1Host: api.example.comContent-Type: application/json{"status": "in_progress"}

    Al igual que cualquier otro campo, puedes usar PATCHel nuevo valor statusy tener algo de lógica en segundo plano para activar cualquier acción importante:

    module States class Trip include Statesman::Machine state :locating, initial: true state :in_progress state :complete transition from: :locating, to: [:in_progress] transition from: :in_progress, to: [:complete] after_transition(from: :locating, to: :in_progress) do |trip| start_trip(trip) end after_transition(from: :in_progress, to: :complete) do |trip| end_trip(trip) end endend

    Statesman es una máquina de estados increíblemente simple para Ruby, escrita por el equipo de GoCardless . Hay muchas otras máquinas de estados en muchos otros lenguajes, pero ésta es fácil de demostrar.

    Básicamente, aquí en algún lugar de sus controladores, libcódigo o lógica DDD , puede verificar si "status"se aprobó la PATCHsolicitud y, de ser así, puede intentar realizar la transición a ella:

     

    resource.transition_to!(:in_progress)

    Cuando se ejecuta este código, realizará la transición con éxito y ejecutará cualquier lógica definida en el after_transitionbloque, o generará un error.

    Las acciones exitosas podrían ser cualquier cosa: enviar un correo electrónico, activar una notificación automática, contactar a otro servicio para comenzar a observar la ubicación GPS del conductor para informar dónde está el automóvil, lo que quiera.

    No había necesidad de un POST /startTripmétodo RPC o un punto final tipo REST POST /trips/123/start, porque simplemente podía manejarse de manera consistente dentro de las convenciones de la API REST.

    Cuando las acciones no pueden ser pensamientos posteriores

    Hemos visto aquí dos enfoques para adaptar acciones dentro de una API REST sin romper su RESTfulness, pero dependiendo del tipo de aplicación para la que se construye la API, estos enfoques pueden comenzar a parecer cada vez menos lógicos y más como saltar obstáculos. Uno podría empezar a preguntarse: ¿Por qué intento incluir todas estas acciones en una API REST? Una API RPC podría ser una excelente alternativa o podría ser un nuevo servicio para complementar una API REST existente. Slack utiliza una API web basada en RPC, porque aquello en lo que está trabajando simplemente no encajaría bien en REST. Imagínese intentar ofrecer opciones de "expulsión", "prohibición" o "abandono" para que los usuarios abandonen o sean eliminados de un solo canal o de todo el equipo de Slack, usando solo REST:

    DELETE /users/jerkface HTTP/1.1Host: api.example.com

    `DELETE` parece ser el método HTTP más apropiado para usar al principio, pero esta solicitud es muy vaga. Podría significar cerrar la cuenta del usuario por completo, lo que podría ser muy diferente a prohibirle el acceso. Si bien podría ser cualquiera de esas opciones, definitivamente no sería patear o irse. Otro enfoque podría ser probar con `PATCH`:

    PATCH /users/jerkface HTTP/1.1Host: api.example.comContent-Type: application/json{"status": "kicked"}

    Esto sería algo extraño, porque el estado del usuario no sería global kickedpara todo, por lo que sería necesario pasarle más información para especificar un canal:

    PATCH /users/jerkface HTTP/1.1Host: api.example.comContent-Type: application/json{"status": "kicked", "kick_channel": "catgifs"}

    Algunas personas intentan esto, pero sigue siendo extraño porque se pasa un nuevo campo arbitrario y, de lo contrario, este campo en realidad no existe para el usuario. Renunciando a ese enfoque, podríamos intentar trabajar con relaciones:

    DELETE /channels/catgifs/users/jerkface HTTP/1.1Host: api.example.com

    Esto es un poco mejor porque ya no estamos jugando con el /users/jerkfacerecurso global, pero todavía le falta una opción de "expulsar", "prohibir" o "dejar", y poner eso en el cuerpo o en la cadena de consulta es, una vez más, solo agregar campos arbitrarios en forma RPC.

    El único otro enfoque que me viene a la mente es crear una kickscolección, una banscolección y una leavescolección, con algunos puntos finales para POST /kicksy puntos finales que coincidan. Estas colecciones permitirían metadatos específicos del recurso, como enumerar el canal del que se está expulsando a un usuario, por ejemplo, pero se siente como forzar una aplicación a un paradigma que no encaja.POST /bansPOST /leaves

     

    La API web de Slack tiene este aspecto:

    POST /api/channels.kick HTTP/1.1Host: slack.comContent-Type: application/json{ "token": "xxxx-xxxxxxxxx-xxxx", "channel": "C1234567890", "user": "U1234567890"}

    ¡Bonito y fácil! Simplemente enviamos argumentos para la tarea en cuestión, tal como lo haría en cualquier lenguaje de programación que tenga funciones.

    Una regla general simple es esta:

    • Si una API se compone principalmente de acciones, tal vez debería ser RPC.
    • Si una API es principalmente CRUD y manipula datos relacionados, tal vez debería ser REST.

    ¿Qué pasa si ninguno de los dos es un claro ganador? ¿Qué enfoque eliges?

    Utilice REST y RPC

    La idea de que es necesario elegir un enfoque y tener solo una API es un poco falsa. Es muy fácil que una aplicación tenga varias API o servicios adicionales que no se consideran la API "principal". Con cualquier API o servicio que exponga puntos finales HTTP, tiene la opción de seguir las reglas de REST o RPC, y tal vez tenga una API REST y algunos servicios RPC. Por ejemplo, en una conferencia, alguien hizo esta pregunta:

    “Tenemos una API REST para gestionar una empresa de hosting web. Podemos crear nuevas instancias de servidor y asignarlas a los usuarios, lo cual funciona muy bien, pero ¿cómo reiniciamos los servidores y ejecutamos comandos en lotes de servidores a través de la API de manera REST?

    No existe una forma real de hacer esto que no sea horrible, aparte de crear un servicio simple estilo RPC que tenga un POST /restartServermétodo y un POST /execServermétodo, que pueda ejecutarse en servidores creados y mantenidos a través del servidor REST.

    Otras lecturas

    • " HTTPS en todas partes con Nginx, Varnish y Apache ", Rachel Andrew
    • “ Una guía para principiantes sobre clientes API JSON basados ​​en jQuery ”, Ben Howdle
    • “ Cómo aplicar transformaciones al diseño web responsivo ”, Ishan Anand
    • " Diseño web adaptable: qué es y cómo utilizarlo ", Vitaly Friedman

    (rb, yk, al, il, nl, mrn)Explora más en

    • Codificación
    • Herramientas
    • javascript
    • Ruby on Rails





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Comprensión de RPC frente a REST para API HTTP

    Comprensión de RPC frente a REST para API HTTP

    Accesibilidad para diseñadores, con Stéphanie Walter SmashingConf Friburgo 2024 Índice ¿Para qué son?

    programar

    es

    https://aprendeprogramando.es/static/images/programar-comprension-de-rpc-frente-a-rest-para-api-http-902-0.jpg

    2024-05-20

     

    Comprensión de RPC frente a REST para API HTTP
    Comprensión de RPC frente a REST para API HTTP

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20