Skip to content

Instantly share code, notes, and snippets.

@carlosvillu
Created September 21, 2012 15:44
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save carlosvillu/3762253 to your computer and use it in GitHub Desktop.
Save carlosvillu/3762253 to your computer and use it in GitHub Desktop.
REST API

Metodos HTTP

  • GET: No altera los datos en el servidor, solo puedes obtener datos de el
  • POST: Crea datos en el server
  • PUT: Altera datos en el server
  • DELETE: Lo borra de forma permanente

También puedes usar POST para hacer llamadas a métodos asíncronos, estos son aquellos que deben de realizar alguna operación que va a requerir más de un tiempo razonable de respuesta ( 100ms en el server ). Si usas POST no deberías de agregar variables GET en la URL.

Códigos de respuesta

#Validos

  • GET 200, 204 ( Respues sin body, sería una respuesta apropiada para un llamada a un método asíncrono )
  • POST 201( Creado ), 206( aceptada, tb es válido para lo métodos asíncronos )
  • PUT 204
  • DELETE 204

#Inválidos

No te compliques 404 en cualquier caso, así tb evitas problemas de seguridad, y no das pistas de más a nadie. Si quieres en desarrollo, puedes usar otros métodos. Pero en producción mejor devolver un 404 siempre.

Elementos de una API

Cuando diseñas la API debes tratar de identificar los siguientes elementos en tu dominio del problema:

  • Documento: Es un concepto único e instanciable. Tal vez un registro en un base de datos y el resultado de una serie de joins en tu bbdd, pero al final debe ser tratada como una unidad atómica de información

  • Colección: Esta claro un grupo de Documentos. Estos son proporcionados por la base de datos y existen físicamente en el servidor.

  • Store: También se usa para aglutinar un conjunto de modelos. PERO estos no forman parte del servidor. Quiero decir que es el usuario de la API quien se encarga de crear o eliminar elementos de esta "collection", Por ejemplo, lo jugadores de un equipo de futbol sin un colección del documento jugador, pero aquellos que para ti son los mejores son un "store" del documento jugador. Espero que más o menos me haya explicado.

  • Controladores: No están relacionados con la información que maneja la api sino con alguna operación que puedas hacer sobre ella. Los controladores pueden ser Síncronos o Asíncronos.

Construcción de la URI

  • El fragmento de la URI que se refiera a un documento debe ser en singular
  • El fragmento de la URI que ser refiera a una colección o a un store, debe ser en plural
  • El fragmento de la URI que se refiera a un controlador deber ser un verbo, pero evitar palabras como get, post, ... please!. Recuerda dios mata a un gatito cada vez que alguien pone /get-players en una api restfull
  • Usa mejor - en lugar de _ en las URIs

Cabeceras

Trata de poner al menos las siguientes cabeceras en todas tus respuetas:

  • Content-Type
  • Content-Length

Por temas de caché puedes usar en aquellas respuestas que tengan body:

  • Last-Modified
  • Etag

HiperMedia

La regla de oro es básicamente, proporciona información para que puedas cambiar de estado.

Es decir, Trata de introducir en todas tus respuesta un link al siguiente estado al que puede pasar la API una vez llegado a ese punto.

Por ejemplo, si estas repondiendo a un método POST con el que has creado un jugador en tu equipo de futbol, podrías en la respuesta poner las URI necesarias para:

  • Ver los detalles del jugador recién creados
  • Eliminar el jugador recién creado

Yo personalmente como mínimo en todas las repuestas a un POST siempre uso la cabecera Location con la URI donde debes de hacer un GET para obtener todos los detalles del jugador.

Esto es tan simple como, crearte un diagrama con cada uno de tus "documentos" y ver segun en que estados estas a que otros estados puedes ir, y luego aportar esa información en la respuesta de la API.

Versionado

Aquí hay mucha discusión cada libro casi dice una cosa distinta, yo estoy colocando la version de la API como el root de todas las URI:

http://api.mipage.com/v1/my/resource

Pero ahora me doy cuenta que ha sido un error muy gordo.

La próxima vez que haga una API, colocaré la versión en la cabecera de TODAS las respuestas:

x-version 1

Para mí es la mejor solución.

Acuerdate de seguir el standart x-loquesa cuando quieras poner cabeceras própias.

Seguridad

Oauth 2, y te quitas de problemas. Te recomiendo el libro Getting Started with OAuth 2.0, 80 páginas de nada está SUPER bien explicado te lo lees en una tarde y te enteras de todo!!! ... aquí me dí cuenta que una cosa es el diseño de la API y otra muy distinta la seguridad!

Espero que te ayude todo esto!

Bibliografía:

@aramirez-es
Copy link

Solo un comentario, aunque es comúnmente usado POST para crear datos y PUT para modificarlos, existe una cierta ambigüedad en el concepto. Según quien hable acerca de esto, puede comentar totalmente lo contrario. El hecho es que ambos sirven para lo mismo, crear y modificar datos. La diferencia entre ambos es que PUT es "idempotent", es decir, si hay dos peticiones PUT idénticas, la segunda no tiene efecto.

Una gran explicación: http://stackoverflow.com/questions/630453/put-vs-post-in-rest/630475#630475

@fiunchinho
Copy link

¿Qué te ha hecho darte cuenta de que ha sido un error muy gordo usar la versión en la URI?

@carlosvillu
Copy link
Author

Muy interesante @aramirez-es, no tenía ni idea. Aunque no me ha quedado muy claro que si PUT es una operación idempotente, entonces, por que no usarla para operaciones más seguras. Quiero decir que para mí es más seguro actualizar un recurso que crearlo desde cero. Pero bueno, supongo que si lo haces usando POST en lugar de PUT ganas que esa es la forma de trabajar del 90% de las librarías rollo Backbone and co.

@carlosvillu
Copy link
Author

Pues por varios motivos @fiunchinho:

  • Una regla básica de las API es que tienes siempre que mantener la compatibilidad hacia atrás con todos los clientes. Y si tienes la versión en la URI, ya estas obligando en cierto modo a tener que cambiar código de los clientes si estas quieres usar la API
  • Estas abusando del concepto de URI ( Uniform resource identifier ), y es que la versión de la API no debe estar relacionado con el recurso que tratas de controlar. Eso forma parte del protocolo de cominucación entre el cliente y el servidor, pero no del recurso en sí mismo.
  • Es mucho más fácil cambiar la versión, si esta no esta en las URI. Yo tengo cosas así en mi código:
app.get '/v1/exam/:id', ( req, res, next ) ->

Te puedes hacer una idea del LIAZO que me va a dar el día que quiera cambiar la versión. Mientras que si fuera una cabecera de la respuesta podría hacer algo así:

app.use (req, res, next) ->
  res.header x-version: app.get 'api current version'
  next()

app.use router

@fiunchinho
Copy link

@carlosvillu estoy de acuerdo en no utilizar la URI para marcar la versión de la API, pero por fomentar algo el debate, te contesto tus puntos :)

  • Tal y como yo entiendo la compatibilidad hacia atrás, si un cliente utiliza las URI's con la versión concreta que desea de la API, y tú mantienes esa versión funcionando para siempre, el cliente nunca notará la diferencia y siempre será compatible. Si ponemos la versión en la cabecera en vez de la URI, y los clientes usan la API sin mandar cabecera para la versión (por desconocimiento o lo que sea), el día que cambiemos la versión "por defecto" para la API los clientes podrían no ser compatibles. Es culpa de los clientes, sí, pero en la URL se hace más explícito que en una cabecera. Esto me hace dudar muchas veces.
  • En este punto estoy totalmente de acuerdo contigo.
  • Este punto no me parece relevante, porque la versión de la API puede ser un valor de configuración que se usa para componer las URIs en el cliente, y de querer cambiar la versión a utilizar, sólo hay que cambiar ese valor en la configuración, sin tener que cambiar todas las URIs una a una.

@fiunchinho
Copy link

@carlosvillu @aramirez-es con respecto al POST vs PUT, creo que la idempotencia y la respuesta de la API son la clave para discernir cual usar. Por muchas veces que yo haga un PUT a una API con los mismos datos, la respuesta de la API será la misma (incluso la ID que la API generó para ese recurso). Sin embargo, si yo hago varias veces un POST con los mismos parámetros, la respuesta cambiará porque la ID que se generó para ese recurso será nueva cada vez. Es decir, no es idempotente, cada vez genera uno.
Ahora ya depende de nuestra aplicación decidir qué comportamiento es el que necesita.

@aramirez-es
Copy link

La definición de Idempotente según la RAE: "Dicho de un elemento de un conjunto: Que tiene la propiedad de que al multiplicarse por sí mismo vuelve a obtenerse el mismo elemento; p. ej., a·a = a.". Como @fiunchinho dice, la respuesta del server siempre será la misma independientemente del número de veces que envíes el mismo elemento via PUT. A diferencia de vía POST, que siempre creará un resource nuevo (identificado mediante un ID único).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment