Saltar al contenido principal

Creación de API con Drizzle ORM y NestJS: guía completa

Cree API con seguridad de tipos con Drizzle ORM y NestJS. Aprenda la definición de esquemas, migraciones, creación de consultas, relaciones, transacciones y patrones de prueba para aplicaciones de producción.

E
ECOSIRE Research and Development Team
|5 de marzo de 20266 min de lectura1.1k Palabras|

Drizzle ORM se ha convertido en el ORM de TypeScript de más rápido crecimiento, ya que ofrece una sintaxis similar a SQL con seguridad de tipos completa y cero sobrecarga de tiempo de ejecución.

Drizzle ORM se ha convertido en el ORM de TypeScript de más rápido crecimiento, ya que ofrece una sintaxis similar a SQL con seguridad de tipos completa y cero sobrecarga de tiempo de ejecución. Combinado con NestJS, crea una potente pila para crear API de producción que sean a la vez fáciles de usar para los desarrolladores y de alto rendimiento.

Conclusiones clave

  • Drizzle proporciona consultas similares a SQL con inferencia completa de TypeScript, sin paso de generación de código
  • La inyección de dependencia de NestJS se integra limpiamente con las conexiones de la base de datos de Drizzle
  • El desarrollo basado en esquemas garantiza que la base de datos y los tipos de TypeScript permanezcan sincronizados
  • Los comandos de inserción y migración de Drizzle manejan la evolución del esquema sin tiempo de inactividad

Configuración del proyecto

Instalación

Comience con un proyecto NestJS y agregue dependencias de Drizzle:

npm install drizzle-orm postgres
npm install -D drizzle-kit @types/pg

Recomendamos el controlador postgres.js por su rendimiento. Para agrupar conexiones en producción, considere PgBouncer o controladores optimizados sin servidor.

Módulo de conexión de base de datos

Cree un módulo de base de datos global que proporcione la instancia de Drizzle mediante inyección de dependencia. Defina un proveedor DB_TOKEN usando useFactory que crea un cliente postgres desde DATABASE_URL y devuelve drizzle(cliente, \\\\\\\\{esquema\\\\\\\\}). Exporte el token para que cualquier servicio pueda inyectarlo con @Inject("DRIZZLE_DB").


Definición del esquema

Defina tablas de bases de datos utilizando los creadores de tablas Drizzle. Cada tabla exporta una constante creada con pgTable() que contiene definiciones de columnas usando uuid, varchar, marca de tiempo, booleana y otros tipos de columnas. Las columnas admiten valores predeterminados (defaultRandom, defaultNow), restricciones (notNull, únicas) y relaciones.

Definición de relaciones

Las relaciones de llovizna proporcionan una carga rápida con seguridad de tipos. Defina relaciones usando la función relaciones(), especificando uno a muchos con muchos() y muchos a uno con uno(). Las columnas de referencia asignan claves externas a las claves primarias de la tabla principal.


Creación de consultas

Seleccionar consultas

Las consultas de llovizna se leen como SQL y al mismo tiempo proporcionan inferencia de tipo completa:

  • Selección simple: db.select().from(usuarios)
  • Filtrado: db.select().from(users).where(and(eq(users.role, "admin"), eq(users.isActive, true)))
  • Con uniones: db.select().from(users).leftJoin(orders, eq(users.id,orders.userId))
  • ** Carga de relaciones **: db.query.users.findMany (\\\\\\\\{ con: { pedidos: verdadero \\\\\\\\}, límite: 20 })

Insertar, actualizar, eliminar

// Insert with returning
const [newUser] = await this.db
  .insert(users)
  .values({ email: "user@example.com", name: "New User" })
  .returning();

// Update
await this.db
  .update(users)
  .set({ role: "admin", updatedAt: new Date() })
  .where(eq(users.id, userId));

// Delete
await this.db.delete(users).where(eq(users.id, userId));

Transacciones

Las transacciones de llovizna garantizan operaciones atómicas. Llame a db.transaction() con una devolución de llamada asíncrona que reciba un objeto de transacción (tx). Todas las consultas dentro de la devolución de llamada se ejecutan de forma atómica; si alguna falla, se revierte toda la transacción.

Los casos de uso comunes incluyen la creación de registros principales y secundarios juntos, la actualización del inventario al procesar pedidos y la transferencia de fondos entre cuentas.


Migraciones

Envío de esquemas (desarrollo)

Durante el desarrollo, el esquema de inserción cambia directamente con la inserción de llovizna-kit. Esto compara sus archivos de esquema con la base de datos y aplica los cambios. Rápido para el desarrollo pero no apto para producción.

Archivos de migración (producción)

Para producción, genere archivos de migración SQL versionados con drizzle-kit generate y luego aplíquelos con drizzle-kit migre. Los archivos de migración se pueden revisar, probar en preparación y aplicar en canalizaciones de CI/CD.


Patrones de integración de NestJS

Patrón de servicio

Los servicios inyectan la base de datos Drizzle y crean consultas con filtros dinámicos:

@Injectable()
export class ProductsService {
  constructor(@Inject("DRIZZLE_DB") private db: DrizzleDB) {}

  async findAll(filters: ProductFilters) {
    const conditions = [];
    if (filters.category)
      conditions.push(eq(products.category, filters.category));
    if (filters.minPrice)
      conditions.push(gte(products.price, filters.minPrice));

    return this.db
      .select()
      .from(products)
      .where(conditions.length ? and(...conditions) : undefined)
      .orderBy(desc(products.createdAt))
      .limit(filters.limit || 20)
      .offset(filters.offset || 0);
  }
}

Multi-inquilino

Para aplicaciones SaaS, cada consulta debe filtrarse por OrganizationId. Cree un servicio base o middleware que garantice el aislamiento de los inquilinos en todas las operaciones de la base de datos. Nunca confíe en los ID de organización proporcionados por el cliente: valídelos con la sesión autenticada.

Consultas parametrizadas

Drizzle utiliza consultas parametrizadas de forma predeterminada, lo que evita la inyección de SQL. Nunca use sql.raw() con la entrada del usuario. En su lugar, utilice el literal de plantilla SQL que parametriza automáticamente los valores interpolados.


Mejores prácticas de rendimiento

  1. Seleccione solo las columnas necesarias: utilice .select(\\\\{ id: usuarios.id, nombre: usuarios.nombre \\\\}) en lugar de seleccionar todas las columnas.
  2. Utilice índices: asegúrese de que las columnas filtradas con frecuencia tengan índices de base de datos
  3. Limitar resultados: utilice siempre .limit() en consultas de lista
  4. Inserciones por lotes: use .values([...array]) para inserciones masivas en lugar de bucles
  5. Agrupación de conexiones: configure tamaños de grupo adecuados para su carga de trabajo
  6. Conexiones diferidas: use un patrón de proxy para posponer la conexión hasta la primera consulta

Preguntas frecuentes

P: ¿Cómo se compara Drizzle con Prisma para NestJS?

Drizzle está más orientado a SQL y no tiene sobrecarga de tiempo de ejecución (sin motor de consultas). Prisma utiliza su propio lenguaje de consulta y requiere un cliente generado. Drizzle tiene un tamaño de paquete más pequeño y arranques en frío más rápidos, mientras que Prisma tiene un ecosistema más grande y más herramientas.

P: ¿Puede Drizzle manejar SQL sin formato complejo?

Sí. El literal de plantilla SQL admite consultas sin formato mientras mantiene la seguridad parametrizada. Drizzle nunca usa concatenación de cadenas para consultas, lo que evita la inyección de SQL.

P: ¿Qué pasa con la agrupación de conexiones en producción?

Utilice PgBouncer externo a la aplicación o configure el controlador postgres.js con límites máximos de conexión. Para entornos sin servidor, utilice controladores optimizados sin servidor con agrupación integrada.

P: ¿Cómo manejamos los cambios de esquema sin tiempo de inactividad?

Genere archivos de migración, revise el SQL, pruebe en etapas y luego aplíquelo en producción. La mayoría de las declaraciones ALTER TABLE en PostgreSQL se ejecutan sin bloqueos exclusivos. Evite operaciones que requieran reescritura de tablas durante las horas pico.


¿Qué sigue?

Drizzle ORM con NestJS proporciona una base de rendimiento y seguridad de tipos para crear API de producción. La API similar a SQL minimiza la brecha de abstracción, mientras que la inferencia de TypeScript elimina los errores de tipo en tiempo de ejecución.

Comuníquese con ECOSIRE para obtener asistencia para el desarrollo de API, o explore nuestros servicios de integración de Odoo para conectar API personalizadas con su ERP.


Publicado por ECOSIRE: ayuda a las empresas a escalar con soluciones de software empresarial.

E

Escrito por

ECOSIRE Team

Technical Writing

The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.

ECOSIRE

Haga crecer su negocio con ECOSIRE

Soluciones empresariales en ERP, comercio electrónico, inteligencia artificial, análisis y automatización.