Zum Hauptinhalt springen

Erstellen von APIs mit Drizzle ORM und NestJS: Vollständiger Leitfaden

Erstellen Sie typsichere APIs mit Drizzle ORM und NestJS. Erfahren Sie mehr über Schemadefinitionen, Migrationen, Abfrageerstellung, Beziehungen, Transaktionen und Testmuster für Produktionsanwendungen.

E
ECOSIRE Research and Development Team
|5. März 20265 Min. Lesezeit919 Wörter|

Drizzle ORM hat sich zum am schnellsten wachsenden TypeScript-ORM entwickelt und bietet SQL-ähnliche Syntax mit vollständiger Typsicherheit und keinem Laufzeitaufwand.

Drizzle ORM hat sich zum am schnellsten wachsenden TypeScript-ORM entwickelt und bietet SQL-ähnliche Syntax mit vollständiger Typsicherheit und keinem Laufzeitaufwand. In Kombination mit NestJS entsteht ein leistungsstarker Stack für die Erstellung von Produktions-APIs, die sowohl entwicklerfreundlich als auch leistungsstark sind.

Wichtige Erkenntnisse

– Drizzle bietet SQL-ähnliche Abfragen mit vollständiger TypeScript-Inferenz – kein Schritt zur Codegenerierung – NestJS-Abhängigkeitsinjektion lässt sich sauber in Drizzle-Datenbankverbindungen integrieren

  • Schemagesteuerte Entwicklung stellt sicher, dass Datenbank- und TypeScript-Typen synchronisiert bleiben – Drizzle Push- und Migrationsbefehle bewältigen die Schemaentwicklung ohne Ausfallzeiten

Projekt-Setup

Installation

Beginnen Sie mit einem NestJS-Projekt und fügen Sie Drizzle-Abhängigkeiten hinzu:

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

Aufgrund seiner Leistung empfehlen wir den Treiber postgres.js. Erwägen Sie für das Verbindungspooling in der Produktion PgBouncer oder serverlos optimierte Treiber.

Datenbankverbindungsmodul

Erstellen Sie ein globales Datenbankmodul, das die Drizzle-Instanz per Abhängigkeitsinjektion bereitstellt. Definieren Sie mit useFactory einen DB_TOKEN-Anbieter, der einen Postgres-Client aus DATABASE_URL erstellt und drizzle(client, \\\\\\\\{ schema \\\\\\\\}) zurückgibt. Exportieren Sie das Token, damit jeder Dienst es mit @Inject("DRIZZLE_DB") einfügen kann.


Schemadefinition

Definieren Sie Datenbanktabellen mit Drizzle-Tabellen-Buildern. Jede Tabelle exportiert eine mit pgTable() erstellte Konstante, die Spaltendefinitionen mit uuid, varchar, timestamp, boolean und anderen Spaltentypen enthält. Spalten unterstützen Standardwerte (defaultRandom, defaultNow), Einschränkungen (notNull, unique) und Beziehungen.

Beziehungen definieren

Drizzle-Beziehungen sorgen für typsicheres Eager Loading. Definieren Sie Beziehungen mit der Funktion „relations()“ und geben Sie „Eins-zu-Viele“ mit „Many()“ und „Viele-zu-Eins“ mit „One()“ an. Referenzspalten ordnen Fremdschlüssel den Primärschlüsseln ihrer übergeordneten Tabelle zu.


Abfrageerstellung

Wählen Sie Abfragen aus

Drizzle-Abfragen lesen sich wie SQL und bieten gleichzeitig eine vollständige Typinferenz:

  • Einfache Auswahl: db.select().from(users)
  • Gefiltert: db.select().from(users).where(and(eq(users.role, "admin"), eq(users.isActive, true)))
  • Mit Joins: db.select().from(users).leftJoin(orders, eq(users.id,orders.userId))
  • Beziehungsladen: db.query.users.findMany(\\\\\\\\{ with: {orders: true \\\\\\\\}, limit: 20 })

Einfügen, Aktualisieren, Löschen

// 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));

Transaktionen

Drizzle-Transaktionen stellen atomare Operationen sicher. Rufen Sie db.transaction() mit einem asynchronen Rückruf auf, der ein Transaktionsobjekt (tx) empfängt. Alle Abfragen innerhalb des Rückrufs werden atomar ausgeführt. Wenn eine Abfrage fehlschlägt, wird die gesamte Transaktion zurückgesetzt.

Zu den häufigsten Anwendungsfällen gehören die gemeinsame Erstellung von übergeordneten und untergeordneten Datensätzen, die Aktualisierung des Lagerbestands bei der Bearbeitung von Bestellungen und die Übertragung von Geldern zwischen Konten.


Migrationen

Schema Push (Entwicklung)

Pushen Sie während der Entwicklung Schemaänderungen direkt mit Drizzle-Kit Push. Dadurch werden Ihre Schemadateien mit der Datenbank verglichen und Änderungen übernommen. Schnell für die Entwicklung, aber nicht für die Produktion geeignet.

Migrationsdateien (Produktion)

Generieren Sie für die Produktion versionierte SQL-Migrationsdateien mit drizzle-kit generic und wenden Sie sie dann mit drizzle-kit migrate an. Migrationsdateien können überprüft, im Staging getestet und in CI/CD-Pipelines angewendet werden.


NestJS-Integrationsmuster

Servicemuster

Dienste injizieren die Drizzle-Datenbank und erstellen Abfragen mit dynamischen Filtern:

@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);
  }
}

Mandantenfähigkeit

Bei SaaS-Anwendungen muss jede Abfrage nach Organisations-ID gefiltert werden. Erstellen Sie einen Basisdienst oder eine Middleware, die die Mandantenisolation bei allen Datenbankvorgängen gewährleistet. Vertrauen Sie niemals den vom Kunden bereitgestellten Organisations-IDs – validieren Sie diese anhand der authentifizierten Sitzung.

Parametrisierte Abfragen

Drizzle verwendet standardmäßig parametrisierte Abfragen und verhindert so die SQL-Injection. Verwenden Sie niemals sql.raw() mit Benutzereingaben. Verwenden Sie stattdessen das SQL-Vorlagenliteral, das interpolierte Werte automatisch parametrisiert.


Best Practices für die Leistung

  1. Nur benötigte Spalten auswählen: Verwenden Sie .select(\\\\\\\\{ id:users.id, name:users.name\\\\\\\\}), anstatt alle Spalten auszuwählen
  2. Indizes verwenden: Stellen Sie sicher, dass häufig gefilterte Spalten über Datenbankindizes verfügen
  3. Ergebnisse begrenzen: Verwenden Sie bei Listenabfragen immer .limit()
  4. Batch-Einfügungen: Verwenden Sie .values([...array]) für Masseneinfügungen anstelle von Schleifen
  5. Verbindungspooling: Konfigurieren Sie geeignete Poolgrößen für Ihre Arbeitslast
  6. Verzögerte Verbindungen: Verwenden Sie ein Proxy-Muster, um die Verbindung bis zur ersten Abfrage zu verschieben

Häufig gestellte Fragen

F: Wie schneidet Drizzle im Vergleich zu Prisma für NestJS ab?

Drizzle ist stärker SQL-orientiert und hat keinen Laufzeitaufwand (keine Abfrage-Engine). Prisma verwendet eine eigene Abfragesprache und erfordert einen generierten Client. Drizzle hat eine kleinere Bündelgröße und schnellere Kaltstarts, während Prisma über ein größeres Ökosystem und mehr Werkzeuge verfügt.

F: Kann Drizzle mit komplexem Roh-SQL umgehen?

Ja. Das SQL-Vorlagenliteral unterstützt Rohabfragen und behält gleichzeitig die parametrisierte Sicherheit bei. Drizzle verwendet niemals eine Zeichenfolgenverkettung für Abfragen und verhindert so die SQL-Injection.

F: Wie sieht es mit Verbindungspooling in der Produktion aus?

Verwenden Sie PgBouncer außerhalb der Anwendung oder konfigurieren Sie den postgres.js-Treiber mit maximalen Verbindungsbeschränkungen. Verwenden Sie für serverlose Umgebungen serverlos optimierte Treiber mit integriertem Pooling.

F: Wie gehen wir mit Schemaänderungen ohne Ausfallzeiten um?

Generieren Sie Migrationsdateien, überprüfen Sie die SQL, testen Sie sie im Staging und wenden Sie sie dann in der Produktion an. Die meisten ALTER TABLE-Anweisungen in PostgreSQL werden ohne exklusive Sperren ausgeführt. Vermeiden Sie Vorgänge, die zu Spitzenzeiten Tabellenumschreibungen erfordern.


Was kommt als nächstes?

Drizzle ORM mit NestJS bietet eine typsichere, leistungsstarke Grundlage für die Erstellung von Produktions-APIs. Die SQL-ähnliche API minimiert die Abstraktionslücke, während TypeScript-Inferenz Laufzeittypfehler eliminiert.

Kontaktieren Sie ECOSIRE für Unterstützung bei der API-Entwicklung oder erkunden Sie unsere Odoo-Integrationsdienste für die Verbindung benutzerdefinierter APIs mit Ihrem ERP.


Herausgegeben von ECOSIRE – unterstützt Unternehmen bei der Skalierung mit Unternehmenssoftwarelösungen.

E

Geschrieben von

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

Erweitern Sie Ihr Geschäft mit ECOSIRE

Unternehmenslösungen in den Bereichen ERP, E-Commerce, KI, Analyse und Automatisierung.