Concepto clave
Integrar una API externa con tipado estricto en TypeScript significa crear una capa de tipos que refleje exactamente el contrato de la API, permitiendo detectar errores en tiempo de compilación en lugar de en tiempo de ejecución. Imagina que estás construyendo un puente entre dos edificios: los tipos son los planos de ingeniería que aseguran que cada conexión sea perfecta y segura. Sin este tipado, trabajar con APIs externas es como construir ese puente sin planos, confiando solo en pruebas manuales para encontrar fallas estructurales.
El tipado estricto para APIs implica definir interfaces o tipos que representen las respuestas, parámetros y errores de la API. Esto no solo mejora la autocompletación en tu editor, sino que también transforma errores potenciales en runtime (como acceder a propiedades inexistentes) en errores de compilación. En arquitecturas complejas, esto es crucial para mantener la consistencia y escalabilidad, especialmente cuando múltiples desarrolladores trabajan en el mismo código base.
Cómo funciona en la práctica
Vamos a integrar una API de clima ficticia paso a paso. Primero, analizamos la documentación de la API para entender su estructura. Supongamos que la API devuelve datos en JSON con este formato:
{
"location": {
"city": "Madrid",
"country": "ES"
},
"current": {
"temp_c": 22.5,
"condition": {
"text": "Soleado",
"icon": "//cdn.apixu.com/weather/64x64/day/113.png"
}
},
"forecast": {
"forecastday": [
{
"date": "2023-10-01",
"day": {
"maxtemp_c": 25.0,
"mintemp_c": 18.0
}
}
]
}
}Creamos interfaces TypeScript que reflejen esta estructura:
interface WeatherCondition {
text: string;
icon: string;
}
interface CurrentWeather {
temp_c: number;
condition: WeatherCondition;
}
interface Location {
city: string;
country: string;
}
interface ForecastDay {
date: string;
day: {
maxtemp_c: number;
mintemp_c: number;
};
}
interface WeatherApiResponse {
location: Location;
current: CurrentWeather;
forecast: {
forecastday: ForecastDay[];
};
}Luego, implementamos una función para hacer la petición usando fetch con tipado:
async function fetchWeather(city: string): Promise {
const response = await fetch(`https://api.weatherapi.com/v1/forecast.json?key=TU_KEY&q=${city}&days=3`);
if (!response.ok) {
throw new Error(`Error en la API: ${response.status}`);
}
const data: WeatherApiResponse = await response.json();
return data;
}Al usar WeatherApiResponse como tipo de retorno, TypeScript verificará que la respuesta coincida con la interfaz. Si la API cambia (por ejemplo, elimina temp_c), obtendrás un error de compilación al intentar acceder a esa propiedad.
Caso de estudio
Considera una aplicación de e-commerce que integra una API de pagos externa. La API devuelve datos de transacciones con una estructura compleja que incluye detalles del usuario, monto, estado y metadatos. Sin tipado, un desarrollador podría asumir incorrectamente que el campo status es un string, cuando en realidad es un número codificado (ej., 1 para "éxito", 2 para "fallido").
Con tipado estricto, definimos:
type PaymentStatus = 1 | 2 | 3; // 1: éxito, 2: fallido, 3: pendiente
interface PaymentResponse {
transactionId: string;
amount: number;
status: PaymentStatus;
user: {
id: string;
email: string;
};
metadata?: Record; // Para datos opcionales
}Al integrar esto en una función de procesamiento:
function handlePayment(response: PaymentResponse) {
if (response.status === 1) {
console.log(`Pago exitoso: ${response.transactionId}`);
} else if (response.status === 2) {
console.error(`Pago fallido para usuario: ${response.user.email}`);
}
// TypeScript previene errores como tratar status como string
}Esto asegura que cualquier desviación de la API sea capturada temprano, reduciendo bugs en producción. En una arquitectura compleja con múltiples microservicios, este enfoque mantiene la consistencia de datos entre sistemas.
Errores comunes
- No validar tipos en runtime: TypeScript solo verifica en compilación, pero las APIs pueden devolver datos inesperados. Usa librerías como Zod o io-ts para validación runtime junto con tipado.
- Tipos demasiado genéricos: Usar
anyounknownsin refinamiento anula los beneficios del tipado. Siempre define interfaces específicas para respuestas de API. - Ignorar errores de API: No tipar los errores lleva a manejo inconsistente. Define un tipo para errores, por ejemplo,
interface ApiError { code: number; message: string; }. - No actualizar tipos tras cambios en la API: Si la API evoluciona, tus tipos deben reflejarlo. Automatiza esto con herramientas como OpenAPI o contrato de tipos.
- Tipar solo respuestas exitosas: Las APIs pueden fallar; incluye tipos para respuestas de error y usa uniones discriminadas, por ejemplo,
type ApiResult<T> = { success: true; data: T; } | { success: false; error: string; }.
Checklist de dominio
- ¿Definiste interfaces TypeScript para todas las respuestas, parámetros y errores de la API?
- ¿Usaste tipos literales o uniones para campos con valores fijos (ej., estados de pago)?
- ¿Implementaste validación en runtime para complementar el tipado estático?
- ¿Probaste tu integración con datos reales de la API para verificar coincidencia de tipos?
- ¿Documentaste los tipos generados para que otros desarrolladores los entiendan?
- ¿Configuraste alertas o pruebas para detectar cambios no compatibles en la API?
- ¿Refactorizaste código existente para usar estos tipos de forma consistente en la arquitectura?
Integrar una API de GitHub con Tipado Estricto
En este ejercicio, integrarás la API pública de GitHub para obtener información de repositorios, aplicando tipado estricto en TypeScript. Sigue estos pasos:
- Analiza la API: Visita
https://api.github.com/repos/microsoft/TypeScripten tu navegador para ver la estructura de respuesta JSON de un repositorio. Observa campos comoname,description,stargazers_count, yowner. - Crea interfaces TypeScript: En un archivo
github-types.ts, define interfaces que representen la respuesta. Incluye al menos:GitHubRepopara el repositorio, con propiedades comoid(number),name(string),stargazers_count(number), yowner(un objeto conloginyavatar_url).GitHubErrorpara errores, conmessage(string) ydocumentation_url(string).
- Implementa una función tipada: En
github-client.ts, crea una funciónfetchRepo(owner: string, repo: string): Promise<GitHubRepo>que use fetch para obtener datos. Asegúrate de manejar errores HTTP y tipar la respuesta comoGitHubRepo. - Añade validación runtime: Usa una librería como Zod (opcional) o escribe una función simple para verificar que la respuesta coincida con tu interfaz, lanzando un error si no es así.
- Prueba la integración: En un archivo
index.ts, llama afetchRepo('microsoft', 'TypeScript')y muestra el nombre y estrellas del repositorio en consola. Ejecuta conts-nodeo compila a JavaScript.
- Usa
typeofo una herramienta como QuickType para generar tipos iniciales a partir del JSON de respuesta. - Considera usar un tipo unión para la función que pueda devolver
GitHubRepo | GitHubErrorpara manejo robusto de errores. - Si la API tiene límites de tasa, incluye lógica para reintentos o manejo de errores 429 en tu función.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.