Introducción al diseño de una API HTTP (Parte 3 de 4) : HTTP Body

Este tercer artículo abarca una breve introducción sobre como estructuramos el contenido (cuerpo) de nuestras respuestas HTTP (HTTP Body).

¿Qué es JSON?

JSON (JavaScript Object Notation) es el formato de serialización preferido para el intercambio de información entre las API HTTP más populares de hoy. La especificación para elaborar documentos JSON es extremadamente simple, con unos ejemplos te convertirás en un experto. Esencialmente, un documento JSON contiene objetos de pares clave: valor, donde los valores pueden ser cadenas de texto, números, valores booleanos, nulos o matrices / objetos de más valores.

Esta facilidad de uso y flexibilidad contrasta con otros formatos de datos como XML (muy usados en SOAP), que a menudo requiere una compleja lógica de serialización y una sintaxis detallada para consultar datos. El siguiente es un documento JSON de ejemplo:

Nombre de Atributo

Cuando usas JSON o en realidad cualquier otro formato, una consideración importante es elegir la forma como vas a nombrar a los atributos (nombre de las claves). Puedes elegir entre estas tres opciones:

snake_case: Este formato usa más bytes pero es más fácil de leer.
PascalCase: Este formato no es tan común, obliga a tener más letras mayúsculas.
camelCase: Este formato es legible y usa menos bytes.

Ninguno de los formato es mejor o peor que los demás. Independientemente del formato que elija, es importante ser coherente a lo largo de sus solicitudes y respuestas. Nunca mezcle tipos de formato, ya que será confuso para los desarrolladores recordar qué formato usar en qué situación. Incluso si su servicio es una fachada para varios servicios diferentes y esos tipos de mezcla de servicios, su servicio deberá elegir un único formato y traducir las propiedades. Es común que los proyectos coincidan con el mismo caso de su API externa con variable interna o nombres de propiedad, sin embargo, no hay beneficio para el consumidor en hacerlo.

Valores booleanos

Siempre que utilice propiedades booleanos en su documento JSON, siempre use palabras “positivas”. El cambio entre contrapartes positivas o negativas es confuso y requerirá que el desarrollador revise con frecuencia la documentación. Aquí hay unos ejemplos:

Use enabled en vez de disabled
Use public en vez de private

Por ejemplo, puede indicar que la información que estas devolviendo de un usuario (en formato JSON), esta habilitado (enabled: TRUE) o no esta habilitado (enabled: FALSE).

Cuando se nombran propiedades booleanas, generalmente es excesivo indicar que una propiedad es booleana con el nombre. Como ejemplo, no hay necesidad de llamar a una propiedad is_cool o cool_flag, basta con decir cool:TRUE o cool:FALSE. Si eliges usar un flag, hazlo consistente en toda la API.

Timestamps

Hay algunos estándares diferentes para serializar un timestamp (marca de tiempo). Sin embargo, un formato gobierna sobre todos ellos, y ese formato es ISO 8601. Aquí hay algunos ejemplos de este formato:

"2017-08-15T09:38:46+00:00": Fecha basada en el desplazamiento del UTC.
"2017-08-15T09:39:46Z": Usando “Zulu” UTC time.
"2017-08-15T09:37:46.987Z": Usando precisión de milisegundos.

Este formato de Timestamp siempre se representa como una cadena. Una buena característica es que, suponiendo que cada timestamp se encuentre en la misma zona horaria, cuando se ordenan alfabéticamente, se ordenarán en función de la ocurrencia. También son muy fáciles de leer para los humanos y, sin embargo, son bastantes flexibles.

Una alternativa común es usar el  Unix Epoch Time, que es un formato ilegible y ambiguo, es como representar una fecha/hora en formato numérico. Un ejemplo de este formato es 1493268311123, que incluye una precisión de milisegundo, que es diferente de 1493268311, que no lo hace. Es imposible conocer la precisión sin contener información de fuera de banda, como por ejemplo, indicar la precisión con anticipación en la documentación.

Versiones

Al construir y mantener una API HTTP, es común realizar cambios que causarán incompatibilidades en los consumidores. Cuando se realizan estos cambios, es vital que permitamos que los clientes antiguos continúen trabajando con la versión anterior de la API, mientras que admiten una nueva versión en paralelo. Esto permite a los clientes migrar a la nueva versión cuando llegue el momento oportuno.

Aquí hay tres métodos populares para versionar una API HTTP:

URL Segment (como lo usan en LinkedIn, Google+, Twitter): https://api.example.org/v1/*
Accept Header (GitHub): Accept: application/json+v1
Custom Header (Joyent CloudAPI): X-Api-Version: 1

Las nuevas versiones de las API solo se deben realizar cuando las operaciones que normalmente funcionarían con la versión anterior fallarían. Como ejemplo, agregar una nueva propiedad opcional a los recursos o una nueva colección no debería requerir una nueva versión. Cambiar un tipo de valor, agregar un parámetro requerido, eliminar un parámetro o colección, cambiar las opciones predeterminadas de filtrado (por ejemplo, Infinity por defecto a 100 resultados por página) son todos ejemplos de cambios hacia atrás.

Cuando desapruebes una versión anterior de la API, dales a los consumidores suficiente tiempo y atención. Intente notificarles de manera proactiva del cambio e incluso, si es posible, proporcione una guía de migración. Siempre dé una fecha límite si la antigua API se desactivará por completo.

Artículos relacionados:

Introducción al diseño de una API HTTP (Parte 2 de 4) : HTTP Responses

Este segundo artículo abarca una breve introducción sobre las respuestas HTTP (HTTP Responses).

¿Qué es un HTTP Response?

Un HTTP Response, es la respuesta que devuelve un servidor web luego de recibir y procesar una solicitud HTTP (HTTP Request) de un cliente. La estructura del mensaje del HTTP Response es similar en formato al HTTP Request. Veamos un ejemplo.

La primera línea se denomina “línea de estado” y contiene dos partes de información. El primero es el protocolo, en este caso HTTP 1.1, seguido de un espacio. La segunda información es el estado de la solicitud (status code), que se compone de una representación numérica del estado (un código de estado) analizable por el emisor, seguida de una nueva línea. En el ejemplo, el código de estado HTTP es 200 OK.

Al igual que un HTTP Request, el HTTP Response contiene una serie de pares de headers (clave: valor). El nombre del header está a la izquierda, seguido de dos puntos y un espacio, y luego el valor, seguido de una nueva línea. Se recomienda que los nombres del header inicien con una letra mayúscula. Los headers pueden repetirse si tienen múltiples valores, por ejemplo, puedes repetir el header Set-Cookie nos permite establecer varias cookies en una sola respuesta.

Los headers son seguidos por un cuerpo (body response) opcional, que requiere dos nuevas líneas de la última cabecera antes del inicio del contenido del cuerpo. Casi todas las respuestas incluirán un cuerpo aunque es técnicamente opcional.

Headers del HTTP Response

Al igual que los headers del HTTP Request, los headers del HTTP Response representan metadatos que envía el servidor al cliente. Por lo general, hacemos uso de un header HTTP estándar, pero a veces es necesario inventar uno propio. Para hacerlo, se sugiere prefijar el nombre del header con X-, como por ejemplo X-Request-ID. La siguiente lista representa los headers más comunes utilizados en un HTTP Response.

Cache-Control: especifica la política del mecanismo de caché. Por ejemplo, si usamos el valor no-cache le estamos diciendo al cliente que no almacene en cache el recurso o colección solicitado.

Content-Language: especifica el idioma del contenido, por ejemplo en-US, lo cual indica que el idioma del contenido del HTTP Response está en ingles.

Content-Length: corresponde al tamaño en bytes del contenido (body) del HTTP Response, si se conoce antes de tiempo.

Content-Type: hace referencia al tipo de contenido del cuerpo, por ejemplo, podemos usar el valor “application/json“, de esta manera le estamos diciendo al cliente que el contenido enviado esta en formato JSON.

Date: Fecha y hora del servidor.

Expires: Fecha y hora en que el contenido debe caducar en el cliente.

Server: utilizado para identificar al servidor.

Hablemos de los códigos de estados HTTP

Los códigos de estado HTTP (ó HTTP Status Code) se separan en diferentes rangos numéricos, cada rango representa una clase diferente de estados. En las siguientes secciones de este artículo describiremos cada rangos así como valores comunes dentro de cada rango.

Códigos de Estado HTTP – Informativos: 1xx

El rango 1XX de los códigos de estado (100 – 199) son códigos informativos de estado. Generalmente, estos códigos de estado son muy poco usados, dependerá si el API que construyas, lo requiere.

101 Switching Protocols: usados para websockets.

Códigos de Estado HTTP – Exitosos: 2xx

El rango 2XX de códigos de estado (200 – 299) son códigos de estado satisfactorios. Señalan al cliente que cualquier operación, tal como crear un recurso o simplemente recuperar uno, se ha completado satisfactoriamente. Generalmente estos códigos de estado son los más consumidos y producidos con mayor frecuencia.

200 OK: significa que el procesamiento y respuesta de servidor fue exitoso.

201 Created: significa que el recurso ha sido creado. Por ejemplo, cuando envías un POST Request puedes esperar este código de estado del servidor.

202 Accepted: significa que el recurso fue creado o modificado con éxito pero el cambio es asíncrono.

204 No Content: significa que la solicitud tuvo éxito pero el HTTP Response no tiene un cuerpo (Response body)

Códigos de Estado HTTP – Redirección: 3XX

El rango 3XX de códigos de estado (300 – 399) se utiliza para redirigir al cliente de un lugar a otro. Los HTTP Response con estos códigos de estado no tienen un cuerpo, sino que hacen uso de un header de ubicación. Contiene una URL a la que se debe redirigir el cliente.

301 Moved Permanently: significa que el recurso esta en una nueva ubicación, sugiere ir a la nueva dirección (URL).

302 Found: significa que el recurso está en la nueva ubicación pero siempre compruebe la antigua ubicación.

Códigos de Estado HTTP – Error del Cliente: 4XX

El rango 4XX de códigos de estado (400 – 499) hace referencia a errores originados por el cliente. Es decir, el servidor encontró un error en la solicitud HTTP del cliente. La operación NO debería haber alterado el estado del servidor. Es importante trabajar con estos códigos de estado en tu API HTTP.

400 Invalid Request: significa que existe un error genérico del cliente.

401 Unauthorized: significa que el cliente debe proporcionar un header de autorización.

403 Forbidden: significa que el cliente no esta autorizado a acceder a dicho recurso.

404 Not Found: significa que el recurso no fue encontrado en el servidor, recurso no existe.

405 Method Not Allowed: significa que el endpoint existe pero no admite el método HTTP de la solicitud.

406 Not Acceptable: significa que el servidor no puede generar una respuesta para el tipo de contenido (content-type) enviado en el header Accept.

Códigos de Estado HTTP – Error del Servidor: 5XX

El rango 5XX de códigos de estado (500 – 599) hace referencia a los errores que se producen en el servidor o tal vez la solicitud no fue recibida. Estos errores deben evitarse a toda costa.

500 Internal Server Error: significa que un error genérico ocurrió en el servidor.

501 Not Implemented: significa que el servidor todavía no admite la combinación de método / endpoint de la solicitud del cliente.

503 Service Unavailable: significa que el servidor no está disponible temporalmente. Por ejemplo, cuando hacemos trabajos de mantenimiento o tenemos la base de datos desconectada.

521 Web Server Is Down: significa que un servidor intermediario no puede conectarse al servidor destino.

Artículos relacionados:

Fuentes de referencia:

  1. Status Code HTTP