Guia de API REST

La mayoría de las aplicaciones que construimos en base a Joko, son aplicaciones que constan de un backend, y varios tipos de clientes consumiendo un API, en la gran mayoría de los casos se trata de un API REST. Describimos aquí guías para el diseño de un API REST, agnóstico de un dominio específico, basada en varios recursos encontrados en Internet, cuyas referencias podrán encontrar al final de este documento, y otras de nuestra propia experiencia. Es decir son recomendaciones que pueden aplicarse a cualquier tipo de problemas que necesite un API.

=Introducción= Joko propone utilizar un API REST para comunicarse con diferentes tipos de aplicaciones. EL API REST es un solo punto de acceso para soportar todas las operaciones de manera independiente a la aplicación que está utilizando la invocación. De esta manera la Web y los móviles (Android y iOS) utilizan la misma versión del API, lo que mejora los tiempos de respuesta y disminuye los costos de mantenimiento.

El API de JOKO está diseñado para seguir -en la medida de lo posible- los principios propuestos por Roy Fielding.

=Swagger. Auto generar la documentación= La documentación mas actualizada que puede existir es la que se genera en base al código fuente. Es por este motivo que promovemos la utilización de Swagger como herramienta para documentar el API.

=Versionado= Dentro del request debe ir la versión específica que se necesita. En caso que no se especifique se asume la última versión. Un ejemplo para el header podría ser: X-API-VERSION: 1.0

=Convenciones generales=
 * 1) Todos los accesos a la API son realizados por HTTPS, y desde un Root URL donde puedo iniciar toda la navegación por los endpoints
 * 2) Todos los datos se envían y reciben en formato JSON
 * 3) Valores vacíos se representan como "null". No se omiten campos
 * 4) Las fechas-horas están en formato ISO 8601: YYYY-MM-DDTHH:MM:SSZ
 * 5) Palabras o recursos compuestos se separan con "-":  spinal-case
 * 6) El BodyCase debe ser siempre del tipo camelCase, ya que serán consumidos por un lenguaje de programación, y nuestros principales clientes usan Java o Javascript
 * 7) El header User-Agent es obligatorio
 * 8) Nonce (number used once) y request signing. Se deben implementar un mecanismos para evitar envíos duplicados de requests, y una firma electrónica para validar la integridad y validez (tiempo de expiración), de los request.

=Convenciones al trabajar con listas= Cuando se retorna una lista de recursos, se debe de retornar un DTO (Data Transfer Object) que contenga potencialmente menos datos que su contraparte en el servidor.

=Recursos=

Utilizar sustantivos en plural
Utilizamos "nouns" (Sustantivos) y no verbs (verbos) para nombrar a los diferentes recursos a ser utilizados con el API. Se utiliza en lo posible el plural.

La excepción a la regla, se da cuando se necesita modelar operaciones (traducción, convertir, cálculos, etc.). Ej: Google Translate API GET https://www.googleapis.com/language/translate/v2?key=INSERT-YOUR-KEY&target=de&q=Hello%20world

Ejemplos correctos

 * GET /clients/1
 * POST /clients
 * PATCH /accounts/1
 * PUT /orders/1
 * DELETE /addresses/1

Ejemplos incorrectos
Esto es común en ejecuciones remotas, NO es recomendado hacerlo en REST:
 * getClient
 * createClient
 * updateAccountBalance
 * addProductToOrder
 * deleteAddress

Relaciones entre recursos
Para acceder o listar relaciones entre recursos debe utilizarse el siguiente formato: GET /tickets/12/messages - Recupera la lista de mensajes para el ticket #12 GET /tickets/12/messages/5 - Recupera el mensaje #5 para el ticket #12

=Listas de recursos= La lista de recursos se devuelven cuando se consulta un recurso en plural. Ejemplo: GET /clients/

Paginación de recursos
La mayoría de las devoluciones de listas largas deben ser paginadas. Las excepciones deben cumplir los siguientes criterios:
 * Siempre se necesitan todos los registros.
 * El número de registros no es muy grande (<200).
 * No se realizan consultas masivas de esta. Ejemplo: Una sola vez luego del login para cargar una lista de recursos.

En los demás casos se deben realizar listas páginadas en la BD. Estas deben cumplir con el siguiente patrón:
 * TODO: Falta agregar el formato de paginación.

Filtrado de recursos
Diferenciamos filtrado de "búsqueda por criterios". Filtrado se realiza sobre una lista de recursos. Una búsqueda puede ser más compleja y en esos casos, se debe utilizar un JSON en el BODY para realizar la búsqueda utilizando un POST.

La forma de filtrar resultados es con el nombre del campo y el valor de igual, o los posibles valores en caso de ser múltiples. Ej. Un sólo valor: /clients?name=juan Varios valores: /clients?name=juan,jose

Orden
Para ordenar las listas, se necesita el o los nombres de los campos, y el tipo de orden. Los dos atributos especiales son:
 * sortBy: El o los campos por los que se ordenará
 * order: Para el tipo de orden existen dos valores posibles: "asc" (Ascendente) y "desc" (descendente). Si no se especifíca el orden debe ser "asc".

=Verbos= Se utilizan los verbos HTTP para señalizar las diferentes operaciones que el sistema puede realizar sobre un recurso particular.

GET

Nunca modifica datos, solamente lee el estado de un recurso y devuelve, 200 OK en caso de éxito. En caso de fallos referirse a la sección de errores.

POST

Crea un nuevo recurso dentro del sistema. En caso que el recurso haya sido creado devuelve 201 CREATED

PUT

Actualiza el recurso identificado por el URL. Devuelve 200 OK en caso que la operación haya sido exitosa.

PATCH

Actualiza el recurso identificado por el URL pero de manera parcial. Devuelve 200 OK en caso que la operación haya sido exitosa.

DELETE

Elimina el recurso identificado por el URL

=Códigos HTTP= Hacemos la siguiente distinción clara para cada uno de los códigos.
 * 2xx: La operación fue exitosa. 200 Exito, 201 creado exitosamente
 * 4xx: La operación no fue exitosa. La responsabilidad es de quien invocó.
 * 5xx: Un fallo en la operación. La responsabilidad es del servidor.

Códigos de error 4xx
Estos son errores que se dieron porque el cliente invocó el API de manera equivocada o porque hubo alguna restricción de negocio. Esto último NO representa un fallo el sistema, sino un control. Por ejemplo: Evitar insertar registros duplicados.

401 Unauthorized El usuario no está autenticado. El servidor no reconoce las credenciales que se utilizaron.

403 Forbidden El usuario no posee privilegios para realizar la invocación

404 Not Found No se encuentra el recurso solicitado.

409 Conflict Hubo un error de datos o alguna restricción.

Detalle del error
Para los mensajes de error, se debe siempre retornar un payload con información que pueda ayudar al developer y también al soporte técnico a diagnosticarlo. Ej: HTTP/1.1 401 Unauthorized {   "code": "user.unauthorized", "status": "Unauthorized", "message": "No access token provided.", "description": "Más información acerca del error si es que amerita." "request_id": "594600f4-7eec-47ca-8012-02e7b89859ce" }

=Patrón para los DTOs= Es importante mantener la siguiente semántica, para tener bien en claro la función de los DTO. Tomamos de ejemplo un proceso de Login:

LoginRequestDTO:

Contiene exclusivamente datos que provienen del request HTTP, o sea con el JSON que trae datos que ingresó el usuario o la aplicación que realiza el request. REQUEST significa que es un pedido para la aplicación. Aquí NO se debe completar con datos calculados internos de la aplicación web, esto no sólo por una cuestión de semántica, sino también como una medida de seguridad. Si proviene del usuario, no debe poder calcularse ya que se podría alterar un valor, así como tampoco debe provenir del usuario valores como el "id" (con el valor de la BD) del registro, u otros datos que no son visibles para el usuario.

LoginResponseDTO:

En un RESPONSE DTO como su nombre lo indica, se transmite sólo información necesaria para el usuario o la aplicación que lo haya solicitado.

LoginDTO:

En caso de que sea necesario campos extra, que ya sean de manejo interno o que sólo sean para manejo interno dentro del backend (Controller<->Service), por ej. un campo calculado o traído de la base de datos o datos intermedios que se necesitan para componer una respuesta compleja para el cliente, y que se usará sólo entre la capa Web y la capa de negocios (Services o Managers usando los patterns de diseño de apps de Joko).

=Enlaces externos=
 * Representational State Transfer (REST) - Roy Fielding
 * https://bourgeois.me/rest/
 * http://www.slideshare.net/jmusser/ten-reasons-developershateyourapi
 * https://medium.com/@zwacky/design-a-beautiful-rest-api-901c73489458#.abbcdnoc2
 * http://blog.octo.com/en/design-a-rest-api/
 * http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
 * https://developer.github.com/v3/