services/api/src/app.js

Overview

Este archivo construye y exporta la aplicación principal de Express para la API de plano-api. Define la configuración global del servidor, monta middleware compartido, expone rutas públicas y privadas, sirve archivos subidos y registra el endpoint de salud.

También fija varios límites de seguridad y comportamiento del runtime. En particular, confía en un único proxy de borde, configura CORS con env.clientOrigin, y trata los webhooks de pagos con body crudo antes del parser JSON.

[!IMPORTANT] Este archivo es el punto de ensamblaje de la API. Aquí se conectan los módulos de autenticación, publicaciones, match, conversaciones, pagos, leads y actividad de listings.

How it works

flowchart TD
    App[Express app]
    Proxy[trust proxy 1]
    Cors[CORS env clientOrigin]
    RawWebhook[payments webhooks raw body]
    JsonParser[express json 10mb]
    Urlencoded[express urlencoded]
    StaticUploads[static uploads directory]
    ApiRoutes[API routes]
    Health[GET api health]
    NotFound[notFound middleware]
    ErrorHandler[errorHandler middleware]

    App --> Proxy
    App --> Cors
    App --> RawWebhook
    RawWebhook --> JsonParser
    App --> JsonParser
    App --> Urlencoded
    App --> StaticUploads
    App --> ApiRoutes
    ApiRoutes --> Health
    App --> NotFound
    NotFound --> ErrorHandler

La aplicación se crea con express() y luego se configura por etapas. Primero ajusta el comportamiento detrás del proxy y habilita CORS para el origen del cliente. Después registra el webhook de pagos con express.raw() para conservar el body original.

A continuación, activa express.json() y express.urlencoded(), expone /uploads como contenido estático y monta el conjunto de rutas API bajo sus prefijos correspondientes. Por último, define /api/health y termina con los middlewares de notFound y errorHandler.

[!NOTE] El webhook de pagos se registra antes de express.json(). Eso preserva el cuerpo crudo que Stripe necesita para verificar la firma.

Key components

  • app — Instancia de Express que centraliza la configuración, el montaje de rutas y el manejo final de errores.
  • env.clientOrigin — Origen permitido para CORS.
  • paymentsWebhooks — Middleware de webhooks montado antes del parser JSON.
  • notFound — Middleware para solicitudes no resueltas.
  • errorHandler — Middleware final de manejo de errores.
  • uploadsDir — Directorio físico que se expone como archivos estáticos.

Data & fields

Configuración de runtime

[
    {
        "name": "env.clientOrigin",
        "type": "string",
        "required": true,
        "description": "Origen permitido por CORS para el cliente."
    },
    {
        "name": "uploadsDir",
        "type": "string",
        "required": true,
        "description": "Ruta absoluta al directorio de archivos subidos que se sirve de forma estática."
    }
]

Middleware global

[
    {
        "name": "trust proxy",
        "type": "number",
        "required": true,
        "description": "Número de saltos de proxy en los que Express confía. En este archivo se fija en 1."
    },
    {
        "name": "express.json limit",
        "type": "string",
        "required": true,
        "description": "Límite máximo de tamaño para cuerpos JSON. En este archivo se fija en 10mb."
    },
    {
        "name": "express.urlencoded extended",
        "type": "boolean",
        "required": true,
        "description": "Activa el parser de formularios URL-encoded con objetos anidados."
    },
    {
        "name": "cors credentials",
        "type": "boolean",
        "required": true,
        "description": "Credenciales CORS. En este archivo se desactiva."
    }
]

Behaviors

  • app.set("trust proxy", 1) — Hace que Express confíe en un único proxy de borde.
  • app.use(cors(...)) — Permite solicitudes desde env.clientOrigin sin credenciales.
  • app.use("/api/payments/webhooks", express.raw(...), paymentsWebhooks) — Conserva el body crudo para la verificación de firma.
  • app.use(express.json({ limit: "10mb" })) — Parsea JSON con un límite de 10 MB.
  • app.use(express.urlencoded({ extended: true })) — Parsea formularios URL-encoded.
  • app.use("/uploads", express.static(uploadsDir)) — Sirve archivos subidos desde disco.
  • app.use(...) para cada módulo de rutas — Monta los módulos funcionales bajo sus prefijos API.
  • app.get("/api/health", ...) — Responde con un estado saludable de la API.
  • app.use(notFound) — Captura rutas no encontradas.
  • app.use(errorHandler) — Maneja errores de forma centralizada.
  • export default app — Expone la instancia para el arranque del servidor.

API

GET /api/health

{
    "title": "Health check",
    "description": "Returns a basic health response for the API service.",
    "method": "GET",
    "baseUrl": "https://<api-host>",
    "endpoint": "/api/health",
    "headers": [],
    "queryParams": [],
    "pathParams": [],
    "bodyType": "none",
    "requestBody": "",
    "formData": [],
    "rawBody": "",
    "responses": {
        "200": {
            "description": "Service is healthy",
            "body": "{\n  \"ok\": true,\n  \"service\": \"plano-api\"\n}"
        }
    }
}

Workflows

1. Create application | Express creates the `app` instance.
2. Configure proxy trust | The app trusts one proxy hop for forwarded client IPs.
3. Register body parsers | JSON and URL-encoded parsers are enabled.
4. Mount special webhook route | Payments webhooks receive raw request bodies first.
5. Serve static uploads | The `/uploads` path exposes stored files.
6. Mount API modules | Feature routes are attached under `/api/...`.
7. Expose health endpoint | `/api/health` returns service status.
8. Attach terminal middlewares | `notFound` and `errorHandler` finish the request chain.

Gotchas & edge cases

[!WARNING] El webhook de pagos depende del body crudo. Si el parser JSON se ejecuta antes, la verificación de firma puede fallar.

[!WARNING] trust proxy está fijado en 1, no en true. El archivo asume un único proxy de borde delante del contenedor.

[!CAUTION] cors usa credentials: false. Esta configuración no habilita credenciales de navegador en las respuestas CORS.

[!NOTE] /uploads sirve archivos reales desde disco. La ruta expuesta coincide con uploadsDir.

Este archivo conecta con varios módulos funcionales del backend. Monta rutas de auth, public, uploads, listings, campaigns, match, conversations, contact-gate, payments, leads, listing-events, listing-likes y listing-comments.

También depende de ./config/env.js, ./middlewares/notFound.js y ./middlewares/errorHandler.js. En conjunto, estos elementos forman el punto de entrada HTTP de la API.