Definition af services og beskeder med Protobuf IDL
Skriv .proto-kontrakter, og generér typesikre klient- og serverstubs ud fra dem.
Definition af services og beskeder med Protobuf IDL er en gratis Bootcamp i backendudvikling med Node.js-lektion på CoddyKit. Dette er lektion 1 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Bootcamp i backendudvikling med Node.js, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Bootcamp i backendudvikling med Node.js-kurset indeholder 4 lektioner i alt.
Hvorfor et IDL?
I en gRPC-mikrotjeneste kommer kontrakten før koden. Du beskriver dine data og dine RPC-metoder i et sproguafhængigt Interface Definition Language (IDL), der kaldes .proto, og genererer derefter typesikre stubber til Node.js, Go, Java og flere ud fra den ene fil.
- Én
.proto-fil er den fælles sandhedskilde for klienten og serveren. - Protocol Buffers (protobuf) er både IDL'et og det binære wire-format.
- Du skriver aldrig serialiseringskoden i hånden — compileren gør det.
I denne lektion lærer du at skrive .proto-kontrakter og omdanne dem til JavaScript-klient- og serverstubber.
En .proto-fils opbygning
Alle moderne .proto-filer begynder med at erklære syntaks-versionen og en pakke. package opretter et navnerum for dine symboler, så to tjenester begge kan definere en User uden navnekonflikter.
syntax = "proto3";— brug altid proto3 til nye tjenester.package— logisk navnerum, som efter generering svarer til en JS-objektsti.- Filen samler
message(datastrukturer) ogservice(RPC-metoder).
// user.proto
syntax = "proto3";
package users.v1;
// A data shape sent over the wire
message User {
string id = 1;
string email = 2;
bool active = 3;
}Meddelelser og feltnumre
En message er en post med typede felter. Tallet efter = er feltets tag, ikke en standardværdi. Tags bruges af protobuf til at identificere hvert felt på det binære wire-format — de skal være unikke i en meddelelse og må aldrig ændres, når de først er taget i brug.
- Feltnavne kan omdøbes frit; tags skal forblive uændrede af hensyn til bagudkompatibilitet.
- Tags fra 1 til 15 bruger én byte, så reserver dem til dine hyppigst anvendte felter.
- Skalartyper:
string,bool,int32,int64,double,bytes.
message Product {
string id = 1; // tag 1 (1 byte on the wire)
string name = 2;
int32 stock = 3;
double price = 4;
bool discontinued = 5;
}Tilknytning fra proto3 til JavaScript-typer
Når du indlæser en .proto-fil med @grpc/proto-loader, knyttes hver protobuf-type til en JavaScript-værdi. Hvis du kender denne tilknytning, undgår du overraskelser under kørsel.
string,bool,int32,floatogdoubleknyttes til JS-typernestring,booleanognumber.int64/uint64knyttes som standard til en streng i JS (tal kan overstigeNumber.MAX_SAFE_INTEGER).bytesbliver til enBuffer.- Uangivne proto3-skalartyper kommer tilbage som deres nulværdi (
"",0,false) — de er aldrigundefinedpå wire-formatet.
// What a decoded User object looks like in Node.js
const user = {
id: 'u_123', // string -> string
email: '', // unset string -> '' (zero value)
active: false, // unset bool -> false
loginCount: '0' // int64 -> string, not number!
};
console.log(typeof user.loginCount); // 'string'Definition af en tjeneste
En service-blok viser de RPC-metoder, som klienter kan kalde. Hver rpc tager præcis én request-meddelelse og returnerer præcis én response-meddelelse. Hvis du pakker request og response ind i dedikerede meddelelser i stedet for at sende rå skalartyper, kan du senere tilføje felter uden at bryde kontrakten.
- Metodenavne skrives efter konventionen i
PascalCase. - Definér altid en request- og en response-meddelelse for hver metode, også selvom den ene er tom.
message GetUserRequest { string id = 1; }
message GetUserResponse { User user = 1; }
service UserService {
// unary: one request -> one response
rpc GetUser(GetUserRequest) returns (GetUserResponse);
rpc CreateUser(CreateUserRequest) returns (User);
}De fire RPC-typer
Nøgleordet stream på hver side af en rpc-erklæring styrer streamingmodellen. Det samme IDL-nøgleord afgør, om din genererede handler modtager en enkelt værdi eller en stream.
- Unary:
rpc Get(Req) returns (Res)— én ind, én ud. - Serverstreaming:
returns (stream Res)— serveren sender mange. - Klientstreaming:
(stream Req)— klienten uploader mange. - Tovejsstreaming:
(stream Req) returns (stream Res).
service OrderService {
rpc GetOrder(GetOrderRequest) returns (Order);
rpc ListOrders(ListOrdersRequest) returns (stream Order);
rpc ImportOrders(stream Order) returns (ImportSummary);
rpc LiveOrders(stream OrderEvent) returns (stream OrderEvent);
}Enums, repeated og indlejrede meddelelser
Ud over skalartyper giver protobuf dig sammensatte datastrukturer til virkelige data.
enum— et afgrænset sæt værdier; det første medlem skal være0og er standardværdien.repeated— en ordnet liste, som afkodes til et JS-Array.- Indlejrede meddelelser modellerer strukturerede underposter.
Sæt præfiks på enum-medlemmer for at undgå navnekonflikter, fordi enum-værdier deler det omgivende navnerum.
enum OrderStatus {
ORDER_STATUS_UNSPECIFIED = 0; // required zero default
ORDER_STATUS_PENDING = 1;
ORDER_STATUS_SHIPPED = 2;
}
message Order {
string id = 1;
OrderStatus status = 2;
repeated LineItem items = 3; // -> JS Array
}
message LineItem {
string sku = 1;
int32 qty = 2;
}Indlæsning af kontrakten i Node.js
I Node genererer du stubber under kørsel med @grpc/proto-loader sammen med @grpc/grpc-js. Loaderen fortolker .proto-filen, og loadPackageDefinition omdanner den til et navigerbart JS-objekt, der bruger din pakkesti som nøgler.
keepCase: truebevarer feltnavnene præcis, som de er skrevet i proto-filen.longs: Stringholder 64-bit-heltal sikre som strenge.- Pakkestien
users.v1bliver tilproto.users.v1.
const protoLoader = require('@grpc/proto-loader');
const grpc = require('@grpc/grpc-js');
const pkgDef = protoLoader.loadSync('user.proto', {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
const proto = grpc.loadPackageDefinition(pkgDef);
const UserService = proto.users.v1.UserService;Implementering af serverstubben
Den genererede UserService giver dig en tjenestedefinition, som du registrerer handlers til. Hver unary-handler modtager (call, callback); call.request er din afkodede request-meddelelse, og du svarer via den Node-lignende callback(err, response).
- Returnér en gRPC-status ved at sende en fejl med en
codefragrpc.status. - Response-objektet skal matche felterne i response-meddelelsen.
const server = new grpc.Server();
server.addService(UserService.service, {
GetUser(call, callback) {
const { id } = call.request;
const user = db.find(id);
if (!user) {
return callback({
code: grpc.status.NOT_FOUND,
message: `User ${id} not found`,
});
}
callback(null, { user });
},
});Kald fra klientstubben
Den samme genererede UserService er også en klientkonstruktør. Du opretter en instans med en måladresse og legitimationsoplysninger og kalder derefter metoder direkte. Hvert unary-kald tager request-objektet og en Node-lignende callback.
credentials.createInsecure()til lokal udvikling; brug TLS i produktion.- Request og response er almindelige JS-objekter, der matcher proto-meddelelserne.
const client = new UserService(
'localhost:50051',
grpc.credentials.createInsecure()
);
client.GetUser({ id: 'u_123' }, (err, res) => {
if (err) {
console.error(err.code, err.message);
return;
}
console.log(res.user.email);
});Sikker videreudvikling af kontrakten
En kontrakt er kun nyttig, hvis den kan ændres uden at ødelægge klienter, der allerede er sat i drift. proto3 gør tilføjende videreudvikling sikker, når du følger nogle få regler.
- Tilføj nye felter med nye, aldrig før anvendte tagnumre — gamle klienter ignorerer dem.
- Genbrug eller omnummerér aldrig tags; markér fjernede tags med
reserved. - Omdøbning af et felt er kompatibel med wire-formatet (det er tagget, der betyder noget), men bryder brug af JSON og tekst.
- Brug
reservedtil både fjernede tagnumre og navne for at forhindre utilsigtet genbrug.
message User {
reserved 4, 5; // retired tags, never reuse
reserved "phone"; // retired field name
string id = 1;
string email = 2;
bool active = 3;
string display_name = 6; // safe additive change
}Hurtigt tjek
Du skal fjerne det forældede phone-felt (tag 4) fra en User-meddelelse, der allerede er sat i drift. Hvad er den korrekte, bagudkompatible måde at gøre det på?
Opsummering
Du har lært at designe og bruge gRPC-kontrakter med Protobuf IDL:
- En
.proto-fil medsyntax = "proto3"og enpackageer den fælles sandhedskilde for klient og server. messagedefinerer typede poster; tallet efter hvert felt er det stabile wire-tag, ikke en standardværdi.service+rpcerklærer metoder; nøgleordetstreamvælger unary-, server-, klient- eller tovejsstreaming.enum,repeatedog indlejrede meddelelser modellerer mere avancerede data;int64afkodes til en JS-streng.- I Node genererer
@grpc/proto-loader+grpc.loadPackageDefinitionbåde servertjenesten og klientkonstruktøren. - Videreudvikl kontrakter ved at tilføje felter, og beskyt pensionerede tags og navne med
reserved.
Lær JavaScript med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 22
- Lektioner
- 92
Ofte stillede spørgsmål
Er lektionen “Definition af services og beskeder med Protobuf IDL” gratis?
Ja — hele teksten til “Definition af services og beskeder med Protobuf IDL” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Bootcamp i backendudvikling med Node.js-kurset, skal du opgradere til CoddyKit PRO. Bootcamp i backendudvikling med Node.js-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Definition af services og beskeder med Protobuf IDL”?
Skriv .proto-kontrakter, og generér typesikre klient- og serverstubs ud fra dem. Du øver dig i Bootcamp i backendudvikling med Node.js med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Bootcamp i backendudvikling med Node.js?
Der kræves ingen tidligere erfaring. Bootcamp i backendudvikling med Node.js på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 1 af 4.
Hvor lang tid tager lektionen “Definition af services og beskeder med Protobuf IDL”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Bootcamp i backendudvikling med Node.js-lektion?
Ja. Alle Bootcamp i backendudvikling med Node.js-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Definition af services og beskeder med Protobuf IDL
- Unary-, server-, client- og bidirectional-streaming-RPC'er
- Interceptors, deadlines og metadata
- Udvikling af protoer og bagudkompatibilitet