Uso de JSON en APIs REST (request y response en formato JSON)

1) Concepto básico

REST es un estilo de arquitectura para servicios web.

JSON es el formato de datos más usado en REST por su ligereza y compatibilidad.

La app cliente (web/móvil/otro servicio) envía HTTP requests y la API responde con HTTP responses (status code + headers + cuerpo JSON).

2) Estructura de un request típico (HTTP)

Componentes clave:

  • Método: GET, POST, PUT, PATCH, DELETE.
  • URL (recurso): https://api.ejemplo.com/productos/101
  • Headers:
    Content-Type: application/json (si envías body)
    Accept: application/json (lo que esperas recibir)
    Authorization: Bearer <token> (si hay auth)
  • Body (en métodos con cuerpo): JSON válido

Ejemplo POST (crear)

POST /productos HTTP/1.1
Host: api.ejemplo.com
Content-Type: application/json
Accept: application/json
Authorization: Bearer <token>

{
  "descripcion": "Teclado mecánico",
  "precio": 1200.50,
  "disponible": true
}

3) Estructura de un response típico (HTTP)

  • Status code (200 OK, 201 Created, 400 Bad Request, 404 Not Found, 500 Internal Server Error)
  • Headers (p. ej. Content-Type: application/json; charset=utf-8)
  • Body — JSON con datos o error

Ejemplo 201 Created

HTTP/1.1 201 Created
Content-Type: application/json
Location: https://api.ejemplo.com/productos/101

{
  "id": 101,
  "descripcion": "Teclado mecánico",
  "precio": 1200.50,
  "disponible": true
}

4) Métodos y semántica

  • GET: leer (no tiene body; seguro).
  • POST: crear .
  • PUT: reemplazar recurso completo.
  • PATCH: actualizar parcialmente.
  • DELETE: borrar recurso.

5) Ejemplos de consumo (cliente)

a) curl (CLI)

# GET (listar)
curl -H "Accept: application/json" https://api.ejemplo.com/productos

# POST (crear)
curl -X POST https://api.ejemplo.com/productos \
  -H "Content-Type: application/json" -H "Accept: application/json" \
  -d '{"descripcion":"Teclado","precio":1200.5,"disponible":true}'

Referencia: curl.

b) JavaScript (fetch)

// GET
const lista = await fetch("/productos", { headers: { Accept: "application/json" } })
  .then(r => r.json());

// POST
const nuevo = await fetch("/productos", {
  method: "POST",
  headers: { "Content-Type": "application/json", "Accept": "application/json" },
  body: JSON.stringify({ descripcion: "Mouse", precio: 850.75, disponible: false })
}).then(r => r.json());

Docs: fetch.

c) Python (requests)

import requests
r = requests.get("https://api.ejemplo.com/productos", headers={"Accept": "application/json"})
productos = r.json()

nuevo = {"descripcion": "Monitor 24", "precio": 1500.0, "disponible": True}
r = requests.post("https://api.ejemplo.com/productos",
                  json=nuevo,
                  headers={"Accept":"application/json"})
data = r.json()

Docs: requests.

d) C# (.NET HttpClient)

using System.Net.Http.Json;

var http = new HttpClient { BaseAddress = new Uri("https://api.ejemplo.com/") };
var productos = await http.GetFromJsonAsync<List<Producto>>("productos");

var creado = await http.PostAsJsonAsync("productos", new { descripcion="Parlantes", precio=999.99, disponible=true });
var body = await creado.Content.ReadFromJsonAsync<Producto>();

Docs: System.Net.Http.Json.

6) Diseño de respuestas JSON

a) Recurso simple

{
  "id": 101,
  "descripcion": "Teclado mecánico",
  "precio": 1200.5,
  "disponible": true
}

b) Colección con paginación y filtros

Query params comunes: ?page=2&limit=20&sort=precio:desc&search=teclado

{
  "data": [
    { "id": 101, "descripcion": "Teclado", "precio": 1200.5, "disponible": true },
    { "id": 145, "descripcion": "Teclado RGB", "precio": 1800.0, "disponible": true }
  ],
  "pagination": { "page": 2, "limit": 20, "total": 87, "pages": 5 },
  "filters": { "search": "teclado", "sort": "precio:desc" }
}

Plano: devolvés la lista directo (más simple). Envoltorio: data + pagination + meta (más extensible). Elegí uno y sé consistente.

7) Errores en JSON (formato recomendado)

Usá un formato consistente y legible. Referencia útil: RFC 7807 (application/problem+json).

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json

{
  "type": "https://api.ejemplo.com/errors/validation",
  "title": "Error de validación",
  "status": 400,
  "detail": "El campo 'precio' debe ser mayor a 0.",
  "errors": {
    "precio": ["Debe ser mayor a 0"]
  }
}

8) Autenticación y autorización (headers)

  • Bearer Token (JWT o similar): Authorization: Bearer <token>
  • API Keys: x-api-key: <clave>
  • OAuth2/OpenID Connect para escenarios avanzados.

Respuestas ante problemas: 401 Unauthorized (no autenticado) y 403 Forbidden (autenticado pero sin permisos).

9) CORS (navegadores)

Permite que un frontend en dominio A consuma API en dominio B. Ver CORS.

Respuestas de la API deben incluir headers como:

Access-Control-Allow-Origin: https://mi-frontend.com
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization

10) Versionado de API

  • En la URL: /v1/productos
  • En header (content negotiation): Accept: application/vnd.miapi.v2+json

11) Caching (mejor rendimiento)

Headers: Cache-Control, ETag, Last-Modified. Ver caché HTTP.

Flujo típico:

Server responde 200 OK + ETag: "abc123".
Cliente reintenta con If-None-Match: "abc123".
Si no cambió: 304 Not Modified (sin body).

12) Idempotencia y seguridad

  • GET: seguro e idempotente (no cambia estado).
  • PUT/DELETE: idempotentes (múltiples llamadas = mismo resultado).
  • POST: no idempotente (cuidado con reintentos; usar claves de idempotencia si la plataforma lo permite).

13) PATCH (actualización parcial)

Dos estilos comunes:

  • Merge Patch (application/merge-patch+json): enviás solo campos a cambiar. Especificación: RFC 7396.
  • JSON Patch (application/json-patch+json): operaciones (add, replace, remove). Especificación: RFC 6902.

Ejemplo Merge Patch

PATCH /productos/101
Content-Type: application/merge-patch+json

{ "precio": 1399.99 }

14) Validación con JSON Schema (servidor/cliente)

Define reglas de tipos, requeridos y rangos. Útil para contratos y tests (contract testing). Ver JSON Schema.

15) Estándares de formato de respuesta

16) Seguridad y robustez

  • Validá y saneá todo input JSON (tipos, rangos, longitud).
  • Limitá tamaño de request (max body size) para evitar abusos.
  • Rate limiting / throttling.
  • Logs sin datos sensibles (o enmascarados).
  • HTTPS siempre.

17) Mini API de ejemplo (contrato)

Recursos

GET /productos        lista (paginada)
GET /productos/{id}  detalle
POST /productos      crear
PUT /productos/{id}  reemplazar
PATCH /productos/{id} actualizar parcial
DELETE /productos/{id} borrar

Modelo (JSON)

{
  "id": 101,
  "descripcion": "Teclado mecánico",
  "precio": 1200.5,
  "disponible": true,
  "tags": ["periférico", "oferta"]
}

Respuesta paginada (GET /productos?page=1&limit=2)

{
  "data": [
    { "id": 101, "descripcion": "Teclado", "precio": 1200.5, "disponible": true },
    { "id": 102, "descripcion": "Mouse", "precio": 850.75, "disponible": false }
  ],
  "pagination": { "page": 1, "limit": 2, "total": 37, "pages": 19 }
}

Error de validación (POST)

{
  "type": "https://api.ejemplo.com/errors/validation",
  "title": "Error de validación",
  "status": 400,
  "errors": {
    "descripcion": ["Debe tener al menos 3 caracteres"],
    "precio": ["Debe ser mayor a 0"]
  }
}

18) Checklist de buenas prácticas

  • Content-Type y Accept en application/json.
  • Respuestas coherentes (mismo formato, mismas claves).
  • Status codes correctos (200/201/204/400/401/403/404/409/422/500).
  • Paginación y filtros en listados.
  • Errores estructurados (RFC 7807).
  • Documentación con OpenAPI.
  • Auth clara (Bearer JWT, API Key, OAuth2).
  • CORS configurado.
  • Caching con ETag/Cache-Control cuando corresponda.
  • Versionado (URL o header).
  • Validación con JSON Schema.

Resumen

JSON es el formato rey de las APIs REST. Dominar headers, métodos, status codes y estructuras de respuesta te permite diseñar y consumir APIs sólidas. Sumá paginación, errores consistentes, validación y seguridad para un API profesional.