Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Diseña APIs como si supieras lo que haces

Diseña APIs como si supieras lo que haces

En la charla se tratan principios básicos de diseño de APIs, así como estandares de cumplimiento REST, y ejemplos prácticos de APIs reales (como facebook, twitter o netflix, marvel comics).

Se tratan conceptos como la semántica de recursos, requests, responses, paginación, errores y versionado.

Charla para OpenSouthCode impartida el 2 de Junio de 2018.

https://www.opensouthcode.org/conferences/opensouthcode2018/program/proposals/158

Francisco M. González

June 02, 2018
Tweet

More Decks by Francisco M. González

Other Decks in Technology

Transcript

  1. Índice - Economía de APIs - API REST - Semántica

    - Requests - Responses - Búsquedas y paginación - Errores - Versionado @fmgonzalez76
  2. Economía de APIs - ¿Cuándo empezamos a hablar de APIs?

    - ¿Tiene sentido en el contexto de una aplicación in-house? - Sí, para consumo propio también tiene sentido. - Aumenta la mantenibilidad y la escalabilidad - Así empiezan los microservicios - APIs como producto final, como modelo de negocio @fmgonzalez76
  3. Modelos de negocio - Por acceso / uso - Cuotas

    - APIs Fremium / Premium - Orientada a desarrolladores @fmgonzalez76
  4. API REST Largo recorrido: - CORBA (1991) - SOAP (1998)

    - REST (2000) - GraphQL? (2015) @fmgonzalez76
  5. API REST - Arquitectura orientada a recursos - No guarda

    el estado - Niveles de cumplimiento: - Uso correcto de URL - Uso correcto de HTTP - Uso correcto de Hypermedia @fmgonzalez76
  6. Semántica de REST (recursos) Vamos a escribir un API para

    mantener nuestros clientes. - /addNewClient - /showClient - /updateClient - /deleteClient - /deleteAllClients - /showAllClients - /showBestClients - … @fmgonzalez76
  7. Semántica de REST (recursos) Vamos a escribir un API para

    mantener nuestros clientes. - /addNewClient - /showClient - /updateClient - /deleteClient - /deleteAllClients - /showAllClients - /showBestClients - … @fmgonzalez76 MAL: - Crece sin control - Difícil de mantener - Funcionalidades redundantes - Inconsistencias
  8. Semántica de REST (recursos) - Todo son recursos. - Nombres

    bien. Verbos mal. - Sólo nombres en plural (consistencia) - Para identificar un único recurso utilizamos un id en la url @fmgonzalez76
  9. Semántica de REST (recursos) Twitter: - GET statuses/show/:id - GET

    statuses/lookup - POST favorites/create/:id https://developer.twitter.com/en/docs/tweets /post-and-engage/overview @fmgonzalez76 Marvel Comics: - GET /v1/public/comics - GET /v1/public/comics/:id - GET /v1/public/series - GET /v1/public/series/:id https://developer.marvel.com/docs
  10. Request en REST (verbos HTTP) - GET /comics - GET

    /comics/:id - POST /comics - PUT /comics/:id - PATCH /comics/:id - DELETE /comics/:id - RESTafarians @fmgonzalez76
  11. Request en REST (verbos HTTP) - GET /characters - GET

    /characters/1234 Recursos anidados - GET /comics/1234/characters - GET /comics/1234/characters/5678 @fmgonzalez76
  12. Request en REST (verbos HTTP) - GET /characters - GET

    /characters/1234 Recursos anidados - GET /comics/1234/characters - GET /comics/1234/characters/5678 @fmgonzalez76
  13. Request en REST (verbos HTTP) - GET /characters - GET

    /characters/1234 Recursos anidados - GET /comics/1234/characters - GET /comics/1234/characters/5678 @fmgonzalez76 Por consistencia. Intentaremos evitar la duplicidad.
  14. Request en REST (verbos HTTP) - POST /characters - PUT

    /characters/1234 - PATCH /characters/1234 - DELETE /characters/1234 Recursos anidados - POST /comics/1234/characters - DELETE /comics/1234/characters/5678 - PUT? PATCH? @fmgonzalez76
  15. Request en REST (Formato) - GET /characters/1234.json - GET /characters/1234.xml

    O mejor, usa el parámetro Accept del HEADER de la petición. - GET /characters/1234 Accept: application/xml, application/json, application/html @fmgonzalez76
  16. Request en REST (Multi idioma) La mejor opción vuelve a

    ser utilizar el parámetro Accept-Languaje del header. Accept-Languaje: es-ES;es;en-US;en @fmgonzalez76
  17. Responses en REST (HTTP Status Codes) 2xx (OK) - 200

    Ok. Para peticiones GET que han sido exitosas - 201 Created. Para peticiones POST de creación que han sido exitosas - 202 Accepted. Para peticiones válidas que serán atendidas en otro momento (tareas encoladas). - 204 No Content. Para peticiones DELETE que han sido exitosas. @fmgonzalez76
  18. Responses en REST (HTTP Status Codes) 3xx (Redirecciones) - 304

    Not Modified. Cuando se asume que el cliente ya tiene esa información y no se quiere devolver la misma información de nuevo. @fmgonzalez76
  19. Responses en REST (Content) GET /characters/1234 { “id”: 1234, “name”:

    Batman, “location”: Gotham city } @fmgonzalez76
  20. Responses en REST (Content envelope) GET /characters/1234 { “data”: {

    “id”: 1234, “name”: Batman, “location”: Gotham city } } @fmgonzalez76
  21. Responses en REST (Content colecciones) GET /characters/ { “data”: [

    { “id”: 1234, “name”: Batman, “location”: Gotham city }, { “id”: 1235, “name”: Robin, “location”: Gotham city }, ... ] } @fmgonzalez76
  22. Responses en REST (Content metas) GET /characters/ { “data”: [

    { “id”: 1234, “name”: Batman, “location”: Gotham city }, ... ], “meta”: { “nextPage”: /characters?page=2, “lastPage”: /characters?page=12 } } @fmgonzalez76
  23. Responses en REST (Content HATEOAS sample) GET /characters/ { “data”:

    [ { “id”: 1234, “name”: Batman, “location”: Gotham city, “_links”: { “self”: /characters/1234, “teams”: /teams?member=1234 } }, ... ] } @fmgonzalez76
  24. Responses en REST (Content HATEOAS sample) Netflix: … "_links" :

    { "self" : { "href" : "https://genie.example.com/api/v3/jobs/425c4a6a-a069-4849-a66e-d08d6e8d1912" }, "output" : { "href" : "https://genie.example.com/api/v3/jobs/425c4a6a-a069-4849-a66e-d08d6e8d1912/output" }, "status" : { "href" : "https://genie.example.com/api/v3/jobs/425c4a6a-a069-4849-a66e-d08d6e8d1912/status" }, ... https://netflix.github.io/genie/docs/3.0.0/rest/ @fmgonzalez76
  25. Responses en REST (jsonApi) GET /characters/1234 { “data”: { “id”:

    1234, “type”: character, “attributes”: { “name”: Batman, “location”: Gotham } } @fmgonzalez76
  26. Responses en REST (jsonApi) { “data”: { “id”: 1234, “type”:

    character, “attributes”: { “name”: Batman, “sidekick”: { “id”: 1235, “type”: character, } } }, “includes”: [ { “id”: 1235, “type”: character, “attributes”: {...} } ] } @fmgonzalez76
  27. Responses en REST (jsonApi) { “data”: { “id”: 1234, “type”:

    character, “attributes”: { “name”: Batman, “sidekick”: { “id”: 1235, “type”: character, } } }, “includes”: [ { “id”: 1235, “type”: character, “attributes”: {...} } ] } @fmgonzalez76
  28. Responses en REST (jsonApi) { “data”: { “id”: 1234, “type”:

    character, “attributes”: { “name”: Batman, “sidekick”: { “id”: 1235, “type”: character, } } }, “includes”: [ { “id”: 1235, “type”: character, “attributes”: {...} } ] } @fmgonzalez76
  29. Búsquedas - Simplifica las relaciones GET /comics/1234/characters - Y lleva

    la complejidad a la query string GET /comics/1234/characters?role=guest&type=hero @fmgonzalez76
  30. Errores - Nunca devolver códigos de error personalizados. - Utilizar

    los códigos de estado de HTTP. - Siempre que sea posible los mensajes de HTTP. @fmgonzalez76
  31. Errores (HTTP Status Codes) 4xx (Errores del cliente) - 400

    Bad Request. Indicamos que no hemos procesado la petición, porque la petición no era válida. - 403 Forbidden. No procesamos la petición, por falta de privilegios. - 404 Not Found. El recurso no existe. - 406 Not Acceptable. No podemos devolver el recurso en el formato solicitado en el Accept header. @fmgonzalez76
  32. Errores (HTTP Status Codes) 5xx (Errores del servidor) - No

    queremos devolver ninguno de estos. @fmgonzalez76
  33. Errores (Códigos propios) Facebook Status Code: 200 OK { “error”:

    { “type”: "Exception", “code”: 103, "message":"Incorrect signature" } } https://developers.facebook.com/docs/marketing-api/error-reference @fmgonzalez76
  34. Versionado (en la url) Marvel Comics GET /v1/public/comics Twitter GET

    /1.1/search/tweets.json?q=from%3ANasa%20OR%20%23nasa @fmgonzalez76
  35. Versionado (en el header) - Añadiendo un parámetro propio en

    el header - Por ejemplo: franci-api-version: 1.1 - Las url siempre son las mismas. - Pero se añade una cabecera no estándar. @fmgonzalez76
  36. Consistencia - Elige un criterio y mantenlo - Documenta tus

    decisiones antes que tu API - Un API consistente es más fácil de utilizar que un API documentada llena de inconsistencias @fmgonzalez76