Services en berichten definiëren in Protobuf
Maak .proto-contracten en genereer getypeerde interfaces voor NestJS-microservices.
Services en berichten definiëren in Protobuf is een gratis Enterprise-backend-API's met NestJS-les op CoddyKit. Dit is les 1 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Enterprise-backend-API's met NestJS. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Enterprise-backend-API's met NestJS bevat in totaal 4 lessen.
Waarom Protobuf het contract bepaalt
In een NestJS gRPC-microservice is het .proto-bestand de enkele bron van waarheid. Het definieert de indeling op de draad, het RPC-oppervlak en — zodra het is gecompileerd — de TypeScript-typen die zowel de client als de server delen.
- Berichten beschrijven de gegevensvormen die over de draad worden verstuurd.
- Diensten declareren de aanroepbare RPC-methoden en hun aanvraag- en antwoordberichten.
In tegenstelling tot REST + OpenAPI (waar het schema vaak na de code wordt geschreven), schrijf je bij gRPC eerst het contract en genereer je daaruit de code. Dit is een contractgestuurd ontwerp.
Anatomie van een .proto-bestand
Elk contract begint met het declareren van de syntaxisversie en een package. Het pakket wordt een naamruimte die NestJS gebruikt om je dienst tijdens runtime te vinden.
syntax = "proto3";— gebruik voor moderne gRPC altijd proto3.package billing;— de naamruimte waarnaar wordt verwezen in de transportopties van NestJS.
Hieronder staat een minimaal maar volledig contract voor een factureringsdienst.
// proto/billing.proto
syntax = "proto3";
package billing;
service InvoiceService {
rpc GetInvoice (GetInvoiceRequest) returns (Invoice);
}
message GetInvoiceRequest {
string id = 1;
}
message Invoice {
string id = 1;
string customer_id = 2;
int64 amount_cents = 3;
string currency = 4;
}Veldnummers zijn het contract
Elk veld heeft een tagnummer (de = 1, = 2...). Deze nummers — niet de veldnamen — worden op de draad gecodeerd.
- Gebruik een bestaand veld nooit opnieuw en nummer het nooit opnieuw; daardoor verbreek je de binaire compatibiliteit met uitgerolde clients.
- Tags 1–15 gebruiken één byte; reserveer ze voor de velden die het vaakst worden verzonden.
- Je mag een veld veilig hernoemen (de naam is lokaal voor de gegenereerde code), maar wijzig het nummer of type nooit.
Wanneer je een veld verwijdert, markeer je het nummer als reserved, zodat het nooit per ongeluk opnieuw wordt gebruikt.
message Invoice {
reserved 5, 6;
reserved "legacy_tax_field";
string id = 1;
string customer_id = 2;
int64 amount_cents = 3;
string currency = 4;
}Scalaire typen en de int64-valkuil
Proto3-scalars worden aan TypeScript gekoppeld, maar die koppeling heeft scherpe randen voor bedrijfs-API's die geldbedragen of ID's verwerken.
string→string,bool→boolean,int32/float/double→number.int64,uint64,fixed64→ worden door de meeste loaders weergegeven alsstring(ofLong), omdat JavaScript-getallen boven 2^53 precisie verliezen.
Voor amount_cents als int64 moet je gegenereerde interface het behandelen als een string, zodat grote waarden niet stilzwijgend worden afgerond.
// Generated-style interface for the Invoice message
export interface Invoice {
id: string;
customerId: string;
// int64 surfaces as string to preserve precision
amountCents: string;
currency: string;
}snake_case erin, camelCase eruit
De Protobuf-conventie gebruikt snake_case voor veldnamen. De NestJS gRPC-loader (@grpc/proto-loader) gebruikt standaard keepCase: false, waardoor velden in de gegenereerde objecten en runtime-objecten worden omgezet naar camelCase.
customer_idin.protowordtcustomerIdin TypeScript.- Als je
keepCase: trueinstelt, moet jecustomer_idletterlijk lezen — dit veroorzaakt vaak fouten metundefined.
Kies per project één conventie en configureer de loader consequent.
// main.ts transport options
import { Transport, GrpcOptions } from '@nestjs/microservices';
import { join } from 'path';
export const grpcOptions: GrpcOptions = {
transport: Transport.GRPC,
options: {
package: 'billing',
protoPath: join(__dirname, 'proto/billing.proto'),
loader: { keepCase: false, longs: String, enums: String },
},
};Enumeraties en hun nulwaarderegel
Proto3-enumeraties moeten een nulwaarde als eerste item definiëren — dit is de impliciete standaardwaarde wanneer een veld op de draad niet is ingesteld.
- Noem de nulwaarde
*_UNSPECIFIED, zodat een niet-ingestelde waarde te onderscheiden is van de "eerste echte toestand". - Enumeraties zijn open in proto3: een client met een nieuwer schema kan een getal verzenden dat je server niet kent, dus verwerk altijd de standaardtak.
Met enums: String in de loader komen waarden in TypeScript aan als hun tekenreeksnamen.
enum InvoiceStatus {
INVOICE_STATUS_UNSPECIFIED = 0;
INVOICE_STATUS_DRAFT = 1;
INVOICE_STATUS_SENT = 2;
INVOICE_STATUS_PAID = 3;
INVOICE_STATUS_VOID = 4;
}
message Invoice {
string id = 1;
InvoiceStatus status = 5;
}De service-interface in NestJS
Elke rpc-methode wordt een methode op een gegenereerde TypeScript-interface. Unaire RPC's retourneren in NestJS een Observable (of Promise) van het antwoordbericht.
Meestal schrijf of genereer je zelf een interface en injecteer je de client via ClientGrpc.getService().
import { Observable } from 'rxjs';
export interface GetInvoiceRequest {
id: string;
}
export interface InvoiceServiceClient {
getInvoice(request: GetInvoiceRequest): Observable<Invoice>;
}
export interface Invoice {
id: string;
customerId: string;
amountCents: string;
currency: string;
status: string;
}De servicehandler implementeren
Aan de serverkant versier je een controllermethode met @GrpcMethod. Het eerste argument is de servicenaam uit de .proto, het tweede is de naam van de rpc-methode.
- De methode ontvangt het gedecodeerde aanvraagbericht als een gewoon object.
- Retourneer rechtstreeks de vorm van het antwoordbericht, of een
Observable/Promisedaarvan.
import { Controller } from '@nestjs/common';
import { GrpcMethod } from '@nestjs/microservices';
@Controller()
export class InvoiceController {
@GrpcMethod('InvoiceService', 'GetInvoice')
getInvoice(data: { id: string }): Invoice {
return {
id: data.id,
customerId: 'cust_42',
amountCents: '120000',
currency: 'EUR',
status: 'INVOICE_STATUS_SENT',
};
}
}Geneste berichten en compositie
Berichten kunnen worden samengesteld. Een veld kan een ander berichttype zijn, zodat je rijke aggregaten kunt modelleren zonder alles tot één vorm plat te slaan.
- Verwijs naar een berichttype met de naam ervan; definieer het ervoor of erna — de volgorde binnen een bestand maakt niet uit.
- Een niet-ingesteld genest bericht komt in TypeScript aan als
undefined, dus controleer dit voordat je de velden ervan benadert.
message Money {
int64 amount_cents = 1;
string currency = 2;
}
message LineItem {
string sku = 1;
uint32 quantity = 2;
Money unit_price = 3;
}
message Invoice {
string id = 1;
string customer_id = 2;
Money total = 3;
repeated LineItem line_items = 4;
}Herhaalde velden, maps en streaming-RPC's
Met deze twee extra bouwstenen zijn de meeste bedrijfscontracten compleet:
repeated T field = N;→ een TypeScript-arrayT[]. Een lege lijst en een niet-ingestelde lijst zijn op de draad niet van elkaar te onderscheiden.map<string, T>→ een TypeScript-record; nuttig voor labels en metagegevens.
Voeg stream toe aan de aanvraag, het antwoord of beide om serverstreaming, clientstreaming of bidirectionele RPC's te declareren. In NestJS gebruiken streamingmethoden @GrpcStreamMethod en werken ze met RxJS-Observable-streams.
service InvoiceService {
rpc GetInvoice (GetInvoiceRequest) returns (Invoice);
// server-streaming: many invoices for one query
rpc ListInvoices (ListInvoicesRequest) returns (stream Invoice);
}
message ListInvoicesRequest {
string customer_id = 1;
map<string, string> filters = 2;
}Getypeerde interfaces genereren met ts-proto
Handmatig geschreven interfaces raken los van de .proto. Gebruik een generator zoals ts-proto (via protoc) om interfaces, helpers voor coderen en decoderen en een NestJS-vriendelijke client-/servicevorm te genereren die synchroon blijft met het contract.
nestJs=truegenereert de gRPC-service-/clientinterfaces die NestJS verwacht.- Voer dit uit in CI, zodat een verouderd gegenereerd bestand de build laat mislukken en code gegarandeerd overeenkomt met het contract.
// package.json script
{
"scripts": {
"proto:gen": "protoc --plugin=node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=./src/generated --ts_proto_opt=nestJs=true,outputServices=grpc-js,useDate=false ./proto/billing.proto"
}
}Korte controle: het contract uitbreiden
Je hebt Invoice uitgebracht met string customer_id = 2;. Een nieuwe vereiste vraagt dat je niet langer customer_id verzendt, maar in plaats daarvan het rijkere geneste bericht Customer customer = 6;. Uitgerolde oudere clients moeten blijven werken.
Samenvatting: contractgestuurde Protobuf
Je kunt nu een servicecontract schrijven en dit omzetten in getypeerde NestJS-interfaces:
- Structuur:
syntax = proto3, eenpackage-naamruimte,message-vormen en eenservicemetrpc-methoden. - Veldnummers vormen het draadcontract — evolueer alleen door toevoegingen; reserveer met
reservedbuiten gebruik gestelde nummers en namen. - Typekoppeling: let op
int64→string, snake_case → camelCase; enumeraties hebben een nulwaarde*_UNSPECIFIEDnodig. - Compositie: geneste berichten,
repeated-arrays,mapenstream-RPC's. - Generatie: leid typen in CI met ts-proto af uit de
.proto, zodat code nooit kan afwijken van het contract.
Leer TypeScript met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 20
- Lessen
- 76
Veelgestelde vragen
Is de les “Services en berichten definiëren in Protobuf” gratis?
Ja — de volledige tekst van “Services en berichten definiëren in Protobuf” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Enterprise-backend-API's met NestJS wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Enterprise-backend-API's met NestJS bevat in totaal 4 lessen.
Wat leer ik in “Services en berichten definiëren in Protobuf”?
Maak .proto-contracten en genereer getypeerde interfaces voor NestJS-microservices. Je oefent met Enterprise-backend-API's met NestJS door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Enterprise-backend-API's met NestJS te beginnen?
Ervaring vooraf is niet nodig. Enterprise-backend-API's met NestJS op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 1 van 4.
Hoe lang duurt de les “Services en berichten definiëren in Protobuf”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Enterprise-backend-API's met NestJS?
Ja. Elke les over Enterprise-backend-API's met NestJS bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Services en berichten definiëren in Protobuf
- gRPC-methoden implementeren en gebruiken
- Streaming-RPC's en backpressure
- Contractevolutie en achterwaartse compatibiliteit