Apariencia
Códigos de Respuesta
Formatos de Respuesta Estándar
La API TSALVA utiliza tres tipos de respuesta estándar que se aplican consistentemente a todos los endpoints.
Respuesta Exitosa (200 Correcto)
Estructura: ApiOKResponse
json
{
"status": true,
"msg": "Se ha creado la oferta exitosamente"
}| Campo | Tipo | Descripción |
|---|---|---|
status | boolean | Siempre true para operaciones exitosas |
msg | string | Mensaje descriptivo del resultado |
Ejemplos por endpoint:
json
// POST /api/v2/oferta
{
"status": true,
"msg": "Se ha creado la oferta exitosamente"
}
// POST /api/v2/asignacion
{
"status": true,
"msg": "Detalles del cliente asignados correctamente"
}
// POST /api/v2/cancelacion
{
"status": true,
"msg": "Servicio cancelado exitosamente"
}Error de Validación (400 Solicitud Incorrecta)
Estructura: ApiInvalidResponse
json
{
"status": false,
"msg": "UUID es requerido"
}| Campo | Tipo | Descripción |
|---|---|---|
status | boolean | Siempre false para errores |
msg | string | Descripción específica del error de validación |
Ejemplos comunes:
json
// Campo requerido faltante
{
"status": false,
"msg": "UUID es requerido"
}
// Formato inválido
{
"status": false,
"msg": "El formato del UUID es inválido"
}
// Valor fuera de rango
{
"status": false,
"msg": "Las coordenadas deben estar en formato decimal"
}
// Recurso no encontrado
{
"status": false,
"msg": "Oferta no encontrada o ya procesada"
}Error Interno (500 Error Interno del Servidor)
Estructura: ApiErrorResponse
json
{
"status": false,
"msg": "Ha ocurrido un error interno del servidor, por favor intenta más tarde"
}| Campo | Tipo | Descripción |
|---|---|---|
status | boolean | Siempre false |
msg | string | Mensaje genérico de error interno |
Códigos de Estado HTTP
| Código | Nombre | Descripción | Cuándo se usa |
|---|---|---|---|
200 | OK | Operación exitosa | Todas las operaciones completadas correctamente |
400 | Bad Request | Error en la petición | Datos faltantes, formato inválido, validación |
401 | Unauthorized | No autorizado | Credenciales inválidas o faltantes |
403 | Forbidden | Prohibido | Permisos insuficientes, restricciones de negocio |
404 | Not Found | No encontrado | Endpoint no existe |
429 | Too Many Requests | Límite excedido | Rate limiting |
500 | Internal Server Error | Error interno | Fallos del sistema, base de datos, etc. |
Respuestas Especiales por Endpoint
POST /api/v2/asignacion-directa
Respuesta exitosa con datos adicionales:
json
{
"status": true,
"msg": "El servicio 'GOT00356' ha sido asignado exitosamente a la central Prestadora ABC",
"codigoServicio": "GOT00356",
"codigoSolicitud": "ABO0036"
}Error de restricción de negocio (403):
json
{
"status": false,
"msg": "No se cumple la condición de cobertura geográfica para la asignación"
}GET /api/v2/types
Respuesta con array de datos:
json
[
{
"id": 1,
"type": "Conductor elegido",
"required_origin": true,
"required_destination": false
},
{
"id": 2,
"type": "Grúa Liviana",
"required_origin": true,
"required_destination": true
}
]POST /api/v2/queries/history
Respuesta con datos históricos:
json
{
"status": true,
"data": [
{
"idServicio": "ABC123456789",
"estado": "Completado",
"fechaCreacion": "2025-07-03T10:30:00Z",
"prestador": "Central Norte SAS",
// ... más campos
}
]
}GET /api/v2/queries/history-options
Respuesta con opciones de filtrado:
json
{
"status": true,
"data": {
"taskStatus": [
{
"id": 1,
"name": "Pendiente"
}
],
"serviceStatus": [
{
"id": 1,
"name": "Activo"
}
],
"businessNits": [
{
"nit": "900000001",
"name": "Empresa ABC SAS"
}
]
}
}Manejo de Errores
Estrategia Recomendada
javascript
async function handleApiResponse(response) {
// Verificar estado HTTP
if (!response.ok) {
if (response.status === 401) {
throw new Error('Credenciales inválidas');
}
if (response.status === 429) {
throw new Error('Límite de peticiones excedido');
}
if (response.status >= 500) {
throw new Error('Error del servidor, reintentar más tarde');
}
}
const data = await response.json();
// Verificar respuesta de la API
if (!data.status) {
throw new Error(data.msg || 'Error desconocido');
}
return data;
}
// Uso
try {
const response = await fetch(url, options);
const result = await handleApiResponse(response);
console.log('Éxito:', result.msg);
} catch (error) {
console.error('Error:', error.message);
}Reintentos para Errores 5xx
javascript
async function apiCallWithRetry(url, options, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status >= 500 && attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000; // Backoff exponencial
console.log(`Intento ${attempt} falló, reintentando en ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
return await handleApiResponse(response);
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
}
}
}Validación de Respuestas
TypeScript Interfaces
typescript
interface ApiOKResponse {
status: true;
msg: string;
}
interface ApiErrorResponse {
status: false;
msg: string;
}
interface AsignacionDirectaResponse extends ApiOKResponse {
codigoServicio: string;
codigoSolicitud?: string;
}
interface HistoryResponse extends ApiOKResponse {
data: HistoryRecord[];
}
// Uso con type guards
function isErrorResponse(response: any): response is ApiErrorResponse {
return response.status === false;
}
function isSuccessResponse(response: any): response is ApiOKResponse {
return response.status === true;
}Buenas Prácticas
- Siempre verifica el campo
statusademás del código HTTP - Implementa reintentos para errores 5xx con backoff exponencial
- Logea tanto errores como respuestas exitosas para debugging
- Valida la estructura de las respuestas antes de procesarlas
Importante
Los mensajes de error pueden cambiar. No dependas de texto específico para lógica de negocio. Usa los códigos de estado HTTP y el campo status para la lógica de control.