No se puede encontrar el módulo: Depuración de las importaciones de Express y los parámetros de ruta
Una API meteorológica de TypeScript Express falla debido a la falta de una importación del controlador. Trace los caminos, la mayúscula y minúscula, así como las exportaciones, y luego valide :city antes de llamar a las APIs meteorológicas en tiempo real.
Depurar una API meteorológica de TypeScript con Express suele enseñar más sobre cómo funciona un backend en Node que cualquier otra explicación abstracta sobre REST.
El error
Después de dividir el proyecto en rutas y controladores, el servidor falló con:
Cannot find module '../controllers/weatherController'
Ese mensaje es común cuando el backend deja de estar en un único archivo. Express está importando weatherController, pero el entorno de ejecución no puede resolver esa ruta de módulo.
Qué verificar
Aborde el problema siguiendo un orden establecido en lugar de adivinar.
¿Existe el archivo? Dentro de src/, el árbol de carpetas debería incluir:
src/
├── controllers/
│ └── weatherController.ts
¿El nombre de la carpeta coincide exactamente? Es preferible usar controllers en lugar de controller o Controllers. Tanto la pluralización como la mayúscula son importantes en sistemas de archivos sensibles a mayúsculas y minúsculas.
¿El nombre del archivo coincide exactamente? Se espera weatherController.ts, y no WeatherController.ts, weathercontroller.ts ni weather-controller.ts. La resolución de módulos en TypeScript considera estos nombres como objetivos diferentes.
¿El camino de importación es correcto? En weatherRoutes.ts, la importación y la configuración de las rutas se ven así:
import { Router } from "express";
import { getWeather } from "../controllers/weatherController";
const router = Router();router.get("/:city", getWeather);export default router;
¿El controlador realmente exporta la función? Un error frecuente es escribir el manejador sin export, por lo que la importación de la ruta no tiene nada a lo que vincularse.
import { Request, Response } from "express";
export const getWeather = (req: Request, res: Response): void => {
const { city } = req.params; res.json({
city,
temperature: 29,
condition: "Cloudy",
humidity: 82,
});
};
Agregar export delante de getWeather restauró el servidor. Una palabra clave, un error resuelto.
Qué abarca el proyecto hasta ahora
En este punto de control, el servicio meteorológico ya incluye varias características propias de una aplicación en producción:
- Una cadena de herramientas de TypeScript para el repositorio
- Un proceso HTTP Express en ejecución
- Directorios separados en lugar de un único archivo enorme
- Ruteadores URL conectados a manejadores
- Módulos de manejador para la lógica de las solicitudes
- Parámetros de ruta como
:city - Cargas útiles JSON estructuradas
- Corrección de errores por módulo faltante mediante verificación local de rutas y exportaciones
Comprensión de los parámetros de ruta
Pruebe la ruta desde un cliente HTTP como Postman:
GET http://localhost:3000/weather/bangalore
GET http://localhost:3000/weather/mumbai
GET http://localhost:3000/weather/chennai
Cada respuesta modifica el campo city. La estructura se mantiene estable: temperature, condition y humidity siguen estando presentes. La cadena con el nombre de la ciudad proviene del segmento de ruta después de /weather/, y se accede a ella mediante req.params.city. Ese es el propósito de un parámetro de ruta: una definición de ruta, pero muchos valores que se sustituyen por solicitud.
El siguiente desafío: validación básica
Una solicitud como la siguiente sigue funcionando con datos de simulación:
GET /weather/123
y devuelve algo similar a:
{
"city": "123",
"temperature": 29,
"condition": "Cloudy",
"humidity": 82
}
El nombre de una ciudad no debe estar formado únicamente por dígitos. Se debe rechazar ese caso en lugar de tratarlo como una entrada meteorológica válida.
Pruebe el parámetro de la ciudad con /^\d+$/. Si hay una coincidencia total, responda con 400 Bad Request en lugar de datos meteorológicos simulados:
res.status(400).json({
error: "City name must contain letters.",
});
De lo contrario, devuelva la carga útil meteorológica normal. Implementar la verificación antes de buscar una respuesta predefinida hace que la regla se cumpla mejor que al pegar un fragmento ya listo.
Verificación rápida de conocimientos
Un breve cuestionario propio confirma las ideas, no solo un compilado casual:
1. ¿En qué se diferencia GET /weather/:city de GET /weather?city=bangalore? Los segmentos de la ruta utilizan un parámetro obligatorio integrado en el patrón de URL. Los valores después de ? son parámetros de consulta y permanecen opcionales. Prefiera los parámetros de ruta cuando el valor identifica al recurso; prefiera los parámetros de consulta para filtros y opciones de activación/desactivación.
2. ¿Por qué usar res.status(400).json() en lugar de simplemente res.json()? Por sí solo, res.json() utiliza por defecto el código 200 OK. Los datos inválidos requieren un estado que indique un fallo, no solo una cadena de error en el cuerpo. Los clientes dependen de ese código.
3. ¿Qué capa gestiona las reglas de negocio: el router, el controlador o otro lugar? Coloque las reglas en los controladores. Los routers solo vinculan el método HTTP y la ruta con un manejador. La validación y las llamadas externas se realizan primero en el controlador y, a medida que la aplicación crece, pasan a un módulo de servicio.
4. ¿Qué contiene req.params.city para GET /weather/mumbai? La cadena "mumbai", tal como se escribió en la ruta.
Qué viene a continuación
El clima simulado ya ha cumplido su función. La siguiente capa es una API meteorológica en tiempo real, lo que implica:
- Llamar a una API HTTP externa
- Variables de entorno (
.env) para que las claves no estén siempre codificadas directamente en el código fuente - Usar
fetchoaxiospara la solicitud saliente - Gestionar de manera adecuada los tiempos de espera y los fallos en el servicio remoto
- Un directorio de servicios para que los controladores no se encarguen directamente del trabajo con el cliente HTTP
La ruta de la solicitud cuenta ahora con otra capa:
Browser/Postman
│
▼
Routes
│
▼
Controllers
│
▼
Services
│
▼
Weather API (external)
Esa estructura en capas es similar a la de muchas aplicaciones Express en producción. Construirla de forma incremental permite tener un punto claro para revertir cambios cuando falla la integración en tiempo real, en lugar de acumular todas las funcionalidades en un solo archivo.
Lecturas relacionadas
- Identificar vs Dar Forma: Elegir Params de Ruta o Cadenas de Pregunta en Express — Aprenda cuándo un valor debe ir en un parámetro de ruta de Express y cuándo en una cadena de pregunta, cómo leer req.params y req.query, y cómo manejar valores por defecto y tipos de manera segura.
- Equilibrar la Generación CRUD de Prisma con un Control Intencional de Rutas — Aprenda cómo la generación basada en esquemas de routers CRUD de Prisma puede eliminar el código repetitivo genérico, manteniendo al mismo tiempo las decisiones relacionadas con la confianza, el alcance y la exposición dentro del código de la aplicación.