Formatos de Respuesta

Comprendiendo las Estructuras de Respuesta de la API

Aprenda sobre los formatos de respuesta de mindzieAPI, códigos de estado, patrones de manejo de errores y estructuras de datos para construir integraciones robustas.

Formato Estándar de Respuesta

Todas las respuestas de mindzieAPI siguen un formato JSON consistente con estructuras predecibles:

Respuesta Exitosa

{
  "data": {
    // Datos principales de la respuesta
  },
  "metadata": {
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "req_12345",
    "version": "1.0.0"
  },
  "pagination": {
    // Presente para respuestas paginadas
    "currentPage": 1,
    "totalPages": 5,
    "totalItems": 100,
    "itemsPerPage": 20,
    "hasNext": true,
    "hasPrevious": false
  }
}

Respuesta de Error

{
  "error": {
    "code": "validation_failed",
    "message": "La validación de la solicitud falló",
    "details": {
      "field": "datasetId",
      "reason": "Formato de GUID inválido"
    },
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "req_12345"
  }
}

Tipos de Respuesta

Respuestas de Éxito

Códigos de estado HTTP 2xx con datos JSON estructurados y metadatos.

Respuestas de Error

Códigos de estado HTTP 4xx/5xx con información detallada de errores.

Paginación

Formato consistente de paginación para respuestas de grandes conjuntos de datos.

Códigos de Estado HTTP

Códigos de Éxito (2xx)

Código Estado Descripción Uso
200 OK Solicitud exitosa, datos devueltos Solicitudes GET, operaciones exitosas
201 Created Recurso creado exitosamente Solicitudes POST que crean nuevos recursos
202 Accepted Solicitud aceptada para procesamiento asíncrono Operaciones de larga duración, tareas en cola
204 No Content Solicitud exitosa, sin datos devueltos Solicitudes DELETE, actualizaciones sin retorno de datos

Códigos de Error del Cliente (4xx)

Código Estado Descripción Causas Comunes
400 Bad Request Formato o parámetros de solicitud inválidos Falta de cabeceras, JSON inválido, datos malformados
401 Unauthorized Requiere autenticación o falló la autenticación Token inválido o faltante, credenciales expiradas
403 Forbidden Autenticación válida pero permisos insuficientes Acceso limitado de usuario, proyecto/tenant incorrecto
404 Not Found El recurso solicitado no existe Endpoint inválido, ID de recurso inexistente
422 Unprocessable Entity Formato válido pero falló la validación de lógica de negocio Reglas de negocio inválidas, violaciones de restricciones
429 Too Many Requests Límite de tasa excedido Demasiadas llamadas a la API en la ventana de tiempo

Códigos de Error del Servidor (5xx)

Código Estado Descripción Acción
500 Internal Server Error Error inesperado del servidor Reintentar con retroceso exponencial
502 Bad Gateway Error en servicio upstream Verificar el estado del servicio, reintentar luego
503 Service Unavailable Servicio temporalmente no disponible Reintentar después de un retraso, verificar mantenimiento
504 Gateway Timeout Tiempo de espera agotado Aumentar timeout, optimizar solicitud

Patrones Comunes de Respuesta

Respuesta de Recurso Único

{
  "actionId": "87654321-4321-4321-4321-210987654321",
  "actionType": "analyze",
  "status": "completed",
  "startTime": "2024-01-15T10:30:00Z",
  "endTime": "2024-01-15T10:32:15Z",
  "duration": 135,
  "result": {
    "outputId": "98765432-8765-4321-4321-987654321098",
    "recordsProcessed": 10000
  }
}

Respuesta de Colección con Paginación

{
  "actions": [
    {
      "actionId": "87654321-4321-4321-4321-210987654321",
      "actionType": "analyze",
      "status": "completed"
    },
    {
      "actionId": "11111111-2222-3333-4444-555555555555",
      "actionType": "export",
      "status": "processing"
    }
  ],
  "pagination": {
    "currentPage": 1,
    "totalPages": 5,
    "totalItems": 100,
    "itemsPerPage": 20,
    "hasNext": true,
    "hasPrevious": false,
    "links": {
      "first": "/api/Action/history?page=1&limit=20",
      "next": "/api/Action/history?page=2&limit=20",
      "last": "/api/Action/history?page=5&limit=20"
    }
  }
}

Respuesta de Operación Asíncrona

{
  "operationId": "op_12345678-1234-1234-1234-123456789012",
  "status": "processing",
  "progress": {
    "percentage": 45,
    "currentStep": "data_analysis",
    "totalSteps": 5,
    "estimatedCompletion": "2024-01-15T10:35:00Z"
  },
  "trackingUrl": "/api/Execution/status/op_12345678-1234-1234-1234-123456789012",
  "message": "Procesando análisis del conjunto de datos..."
}

Detalles de Respuesta de Error

Error de Validación

{
  "error": {
    "code": "validation_failed",
    "message": "La validación de la solicitud falló",
    "details": {
      "errors": [
        {
          "field": "datasetId",
          "code": "invalid_format",
          "message": "Debe ser un GUID válido"
        },
        {
          "field": "parameters.timeout",
          "code": "out_of_range",
          "message": "Debe estar entre 1 y 3600 segundos"
        }
      ]
    },
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "req_12345"
  }
}

Error de Autenticación

{
  "error": {
    "code": "invalid_token",
    "message": "El token de acceso proporcionado es inválido o ha expirado",
    "details": {
      "tokenType": "bearer",
      "expiresAt": "2024-01-15T09:00:00Z",
      "suggestion": "Por favor, actualice su token de acceso"
    },
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "req_12345"
  }
}

Error de Límite de Tasa

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Límite de tasa excedido para este endpoint",
    "details": {
      "limit": 100,
      "remaining": 0,
      "resetTime": "2024-01-15T11:00:00Z",
      "retryAfter": 1800
    },
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "req_12345"
  }
}

Encabezados de Respuesta

Encabezados Estándar

Encabezado Descripción Ejemplo
Content-Type Formato de respuesta application/json; charset=utf-8
X-Request-Id Identificador único de la solicitud req_12345678
X-Response-Time Tiempo de procesamiento del servidor 145ms
X-API-Version Versión de la API usada 1.0.0

Encabezados de Límite de Tasa

Encabezado Descripción Ejemplo
X-RateLimit-Limit Máximo de solicitudes por ventana 100
X-RateLimit-Remaining Solicitudes restantes en la ventana 95
X-RateLimit-Reset Timestamp para reinicio de ventana 1642251600
Retry-After Segundos a esperar antes de reintentar 3600

Mejores Prácticas para Manejo de Errores

Ejemplo en JavaScript

async function handleAPIResponse(response) {
  // Verificar si la respuesta es correcta
  if (!response.ok) {
    const errorData = await response.json();

    switch (response.status) {
      case 400:
        throw new ValidationError(errorData.error.message, errorData.error.details);
      case 401:
        throw new AuthenticationError('Autenticación fallida');
      case 403:
        throw new AuthorizationError('Permisos insuficientes');
      case 404:
        throw new NotFoundError('Recurso no encontrado');
      case 429:
        const retryAfter = response.headers.get('Retry-After');
        throw new RateLimitError(`Límite de tasa alcanzado. Reintentar después de ${retryAfter} segundos`);
      case 500:
      case 502:
      case 503:
      case 504:
        throw new ServerError('Ocurrió un error en el servidor. Por favor reintente.');
      default:
        throw new APIError(`Error inesperado: ${response.status}`);
    }
  }

  return await response.json();
}

// Uso con lógica de reintentos
async function apiCallWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      return await handleAPIResponse(response);
    } catch (error) {
      if (error instanceof RateLimitError) {
        const retryAfter = parseInt(error.retryAfter) || Math.pow(2, attempt);
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
        continue;
      }

      if (error instanceof ServerError && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000; // Retroceso exponencial
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

      throw error;
    }
  }
}

Ejemplo en Python

import requests
import time
from typing import Dict, Any

class APIError(Exception):
    def __init__(self, message: str, status_code: int = None, details: Dict = None):
        super().__init__(message)
        self.status_code = status_code
        self.details = details

def handle_api_response(response: requests.Response) -> Dict[str, Any]:
    """Maneja la respuesta de la API con manejo correcto de errores"""

    if response.ok:
        return response.json()

    try:
        error_data = response.json()
    except ValueError:
        error_data = {"error": {"message": response.text}}

    error_info = error_data.get("error", {})
    message = error_info.get("message", f"HTTP {response.status_code}")
    details = error_info.get("details", {})

    if response.status_code == 429:
        retry_after = response.headers.get('Retry-After', '60')
        raise APIError(f"Límite de tasa alcanzado. Reintentar después de {retry_after} segundos",
                      response.status_code, details)

    elif response.status_code >= 500:
        raise APIError(f"Error del servidor: {message}", response.status_code, details)

    elif response.status_code >= 400:
        raise APIError(f"Error del cliente: {message}", response.status_code, details)

    raise APIError(f"Error inesperado: {message}", response.status_code, details)

def api_call_with_retry(url: str, method: str = 'GET', max_retries: int = 3, **kwargs) -> Dict[str, Any]:
    """Realiza llamada a la API con lógica automática de reintentos"""

    for attempt in range(1, max_retries + 1):
        try:
            response = requests.request(method, url, **kwargs)
            return handle_api_response(response)

        except APIError as e:
            if e.status_code == 429:
                retry_after = int(e.details.get('retryAfter', 60))
                time.sleep(retry_after)
                continue

            elif e.status_code >= 500 and attempt < max_retries:
                delay = 2 ** attempt  # Retroceso exponencial
                time.sleep(delay)
                continue

            raise

    raise APIError(f"Máximo número de reintentos ({max_retries}) excedido")

Próximos Pasos

Ahora que comprende los formatos de respuesta, explore secciones específicas de la API como Actions, Blocks o Datasets para ver estos patrones en acción.