Ir al contenido principal

    Construyendo una API GraphQL code-first para seguridad vehicular: Decisiones y lecciones

    8 min lecturatecnicoarquitecturaGraphQL

    Cuando empezamos a construir la API de Lominic, teniamos un requisito inusual: necesitabamos servir datos a una app movil con conexiones intermitentes, un panel web para municipalidades con dashboards complejos, y un sistema de alertas en tiempo real — todo desde la misma API.

    Elegimos GraphQL con un enfoque code-first sobre NestJS. Dos anos despues, con la API sirviendo a 17 paises, podemos decir que fue la decision correcta — aunque no por las razones que pensabamos inicialmente. En este articulo compartimos las decisiones arquitectonicas que tomamos, por que las tomamos, y que hariamos diferente si empezaramos hoy.

    Por que GraphQL (y no REST)

    La decision de usar GraphQL sobre REST no fue ideologica — fue pragmatica. Teniamos tres clientes con necesidades muy distintas.

    La app movil necesitaba eficiencia de datos: cada byte cuenta cuando tu usuario esta en una red 3G escaneando patentes en la calle. Con GraphQL, la app pide exactamente los campos que necesita — ni mas ni menos. Un query de verificacion de patente devuelve solo el estado y la alerta, no todo el historial del vehiculo.

    El panel municipal necesitaba flexibilidad: dashboards complejos con multiples graficos que combinan datos de distintas fuentes. Con REST, cada dashboard requeriria multiples endpoints o endpoints especializados. Con GraphQL, el frontend compone exactamente la consulta que necesita.

    El sistema de alertas necesitaba tiempo real: cuando se detecta un vehiculo robado, la notificacion debe llegar en segundos. Las suscripciones de GraphQL sobre WebSocket resuelven esto de forma nativa.

    Code-first: el esquema como consecuencia del codigo

    En el enfoque code-first, no escribes un archivo de esquema GraphQL manualmente. En su lugar, defines tus tipos como clases TypeScript con decoradores, y el framework genera el esquema automaticamente. El resultado es que tu codigo y tu esquema estan siempre sincronizados — es imposible que diverjan.

    Las ventajas en la practica son significativas. TypeScript valida los tipos en tiempo de compilacion, lo que significa que un error de tipo en una respuesta GraphQL se detecta antes de llegar a produccion. Los decoradores son expresivos: puedes marcar un campo como nullable, agregar una descripcion, o definir un valor por defecto directamente en la clase.

    La principal desventaja es que el esquema generado puede ser menos legible que uno escrito a mano. Pero como el esquema se genera automaticamente en cada build, esto es un problema estetico, no funcional.

    Arquitectura modular: cada dominio es un modulo

    NestJS promueve una arquitectura modular donde cada dominio del negocio se encapsula en su propio modulo. Cada modulo tiene tres capas con responsabilidades claras.

    El resolver es la capa de entrada: recibe la consulta GraphQL, extrae los parametros, y delega al servicio. Los resolvers deben ser delgados — idealmente menos de 10 lineas por metodo. No contienen logica de negocio.

    El servicio contiene toda la logica de negocio: validaciones, calculos, orquestacion de datos. Es la capa que se testea unitariamente con mayor profundidad.

    Los tipos definen la forma de los datos: tipos de salida (lo que el cliente recibe), tipos de entrada (lo que el cliente envia), y tipos compartidos (paginacion, rangos de fecha, bounding boxes) que se reutilizan entre modulos.

    Esta separacion no es solo organizacional — es fundamental para la mantenibilidad. Cuando un nuevo desarrollador se une al equipo, puede entender un modulo completo sin necesitar contexto del resto del sistema.

    Autenticacion y autorizacion: una cadena de guards

    La seguridad en una API que maneja datos vehiculares y de ubicacion no es opcional. NestJS ofrece un sistema de guards (guardias) que se ejecutan antes de cada operacion, y nosotros lo aprovechamos al maximo.

    La cadena de autorizacion funciona en capas. Primero, se valida que el token de autenticacion sea valido. Luego, se verifica si el usuario ha completado la verificacion de identidad requerida. Finalmente, para operaciones sensibles, se verifica que el usuario tenga el rol adecuado (usuario, operador municipal, administrador).

    Un aprendizaje importante fue que los guards de rol no deben ser globales. Es tentador aplicar un guard de roles a toda la aplicacion, pero en la practica descubrimos que es mas seguro y mas explícito declarar los guards a nivel de cada resolver. Esto evita sorpresas donde un endpoint queda expuesto porque alguien asumio que el guard global lo cubria.

    Suscripciones: el tiempo real que importa

    Las suscripciones de GraphQL permiten que el servidor envie datos al cliente cuando ocurre un evento, sin que el cliente tenga que preguntar periodicamente. En una app de seguridad vehicular, esto es critico.

    Cuando un usuario escanea una patente y detecta un vehiculo con encargo, esa deteccion genera eventos que se distribuyen a multiples interesados: el propietario del vehiculo recibe una notificacion, el operador municipal de la zona recibe una alerta, y el dashboard de administracion se actualiza en tiempo real.

    Internamente, usamos un sistema de publicacion/suscripcion que conecta los servicios de negocio con las suscripciones GraphQL. Cuando un servicio genera un evento, lo publica en un canal. Las suscripciones que estan escuchando ese canal reciben el evento y lo envian al cliente via WebSocket.

    La leccion mas importante con las suscripciones es la gestion de conexiones. Los dispositivos moviles abren y cierran conexiones constantemente (por cambios de red, modo avion, o simplemente al poner la app en segundo plano). El sistema debe manejar reconexiones gracefully sin perder eventos criticos.

    El pipeline de codegen: del servidor al cliente

    Una de las ventajas mas potentes de GraphQL code-first es el pipeline de generacion automatica de codigo. El flujo es el siguiente: los decoradores en el codigo del servidor generan un esquema GraphQL. Ese esquema se usa para generar automaticamente los tipos y hooks de consulta para los clientes (web y movil).

    El resultado es que cuando un desarrollador agrega un campo nuevo a un tipo en el servidor, los clientes obtienen automaticamente un tipo TypeScript actualizado. Si el frontend intenta usar un campo que no existe o lo usa con el tipo incorrecto, TypeScript lo detecta en tiempo de compilacion.

    Este nivel de seguridad de tipos de extremo a extremo es dificil de lograr con REST y es, en nuestra experiencia, una de las ventajas mas concretas de GraphQL en un equipo que trabaja con TypeScript en ambos lados.

    Lo que hariamos diferente

    Dos anos de produccion nos dieron varias lecciones que compartiríamos con cualquier equipo evaluando una arquitectura similar.

    Definir limites de complejidad desde el inicio. GraphQL permite consultas arbitrariamente complejas. Sin limites, un cliente puede construir una consulta que consume recursos excesivos del servidor. Implementamos limites de profundidad y complejidad, pero habria sido mejor tenerlos desde el dia uno.

    Invertir en testing de integracion temprano. Los tests unitarios de servicios son esenciales, pero no detectan problemas de serializacion, autorizacion o suscripciones. Los tests de integracion que ejercitan el flujo completo (query → resolver → service → base de datos) deberian ser prioridad, no una adicion tardia.

    Estandarizar los patrones de error desde el principio. GraphQL tiene su propio sistema de errores que difiere de los codigos HTTP. Definir tempranamente como se representan errores de validacion, autorizacion y negocio en el esquema GraphQL ahorra muchos dolores de cabeza posteriores.

    Preguntas frecuentes

    Que es GraphQL code-first?

    Es un enfoque donde el esquema GraphQL se genera automaticamente a partir del codigo TypeScript, en lugar de escribirse manualmente. Esto mantiene codigo y esquema siempre sincronizados.

    Por que Lominic eligio NestJS para su API?

    NestJS ofrece arquitectura modular, inyeccion de dependencias madura, integracion nativa con GraphQL code-first, y un ecosistema de guards e interceptors que simplifica la autenticacion y autorizacion.

    GraphQL tiene ventajas sobre REST para apps moviles?

    Si. GraphQL permite que la app pida exactamente los datos que necesita en una sola solicitud, reduciendo consumo de datos y latencia — especialmente importante en redes moviles lentas.


    Estas decisiones arquitectonicas alimentan una plataforma que opera en 17 paises de America Latina. Descarga Lominic y experimenta el resultado.

    Verifica cualquier vehiculo gratis

    Consulta si un vehiculo tiene encargo por robo en segundos. Gratis, sin registro y disponible 24/7.

    Descargar App