0Pricing
NestJS Enterprise Backend APIs · Ders

Protobuf'ta Hizmetleri ve Mesajları Tanımlama

.proto sözleşmeleri oluşturun ve NestJS mikro hizmetleri için türü belirlenmiş arayüzler üretin.

Protobuf'ta Hizmetleri ve Mesajları Tanımlama, CoddyKit'te ücretsiz bir NestJS Enterprise Backend APIs dersidir. Bu, 4 dersinin 1. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, NestJS Enterprise Backend APIs öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. NestJS Enterprise Backend APIs kursu toplamda 4 dersten oluşur.

Bu dersin bazı bölümleri henüz çevrilmemiş olup İngilizce olarak gösterilmektedir.

Why Protobuf Drives the Contract

In a NestJS gRPC microservice, the .proto file is the single source of truth. It defines the wire format, the RPC surface, and — once compiled — the TypeScript types both client and server share.

  • Messages describe the data shapes that travel over the wire.
  • Services declare the callable RPC methods and their request/response messages.

Unlike REST + OpenAPI (where the schema is often written after the code), with gRPC you author the contract first and generate code from it. This is contract-first design.

Anatomy of a .proto File

Every contract starts by declaring the syntax version and a package. The package becomes a namespace that NestJS uses to locate your service at runtime.

  • syntax = "proto3"; — always proto3 for modern gRPC.
  • package billing; — the namespace referenced in the NestJS transport options.

Below is a minimal but complete contract for an invoicing service.

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

Field Numbers Are the Contract

Each field has a tag number (the = 1, = 2...). These numbers — not the field names — are what gets encoded on the wire.

  • Never reuse or renumber an existing field; doing so breaks binary compatibility with deployed clients.
  • Tags 1–15 use one byte; reserve them for the most frequently sent fields.
  • You may safely rename a field (the name is local to generated code), but never change its number or type.

When you remove a field, mark its number reserved so it is never accidentally recycled.

message Invoice {
  reserved 5, 6;
  reserved "legacy_tax_field";

  string id = 1;
  string customer_id = 2;
  int64 amount_cents = 3;
  string currency = 4;
}

Scalar Types and the int64 Trap

Proto3 scalars map to TypeScript, but the mapping has sharp edges for enterprise APIs handling money or IDs.

  • string → string, bool → boolean, int32/float/double → number.
  • int64, uint64, fixed64 → represented as string (or Long) by most loaders, because JS numbers lose precision beyond 2^53.

For amount_cents as int64, your generated interface should treat it as a string to avoid silent rounding on large values.

// 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 In, camelCase Out

Protobuf convention is snake_case for field names. The NestJS gRPC loader (@grpc/proto-loader) defaults to keepCase: false, which converts fields to camelCase in the generated/runtime objects.

  • customer_id in .proto becomes customerId in TypeScript.
  • If you set keepCase: true, you must read customer_id verbatim — this is a frequent source of undefined bugs.

Pick one convention per project and configure the loader consistently.

// 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 },
  },
};

Enums and Their Zero-Value Rule

Proto3 enums must define a zero value as the first entry — it is the implicit default when a field is unset on the wire.

  • Name the zero value *_UNSPECIFIED so unset and "first real state" are distinguishable.
  • Enums are open in proto3: a client on a newer schema may send a number your server does not know, so always handle the default branch.

With enums: String in the loader, values arrive as their string names in TypeScript.

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

The Service Interface in NestJS

Each rpc method becomes a method on a generated TypeScript interface. Unary RPCs return an Observable (or Promise) of the response message in NestJS.

You typically hand-write or generate an interface and inject the 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;
}

Implementing the Service Handler

On the server side, decorate a controller method with @GrpcMethod. The first argument is the service name from the .proto, the second is the rpc method name.

  • The method receives the decoded request message as a plain object.
  • Return the response message shape directly, or an Observable/Promise of it.
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',
    };
  }
}

Nested Messages and Composition

Messages compose. A field can be another message type, letting you model rich aggregates without flattening everything into one shape.

  • Reference a message type by name; define it before or after — order does not matter within a file.
  • An unset nested message arrives as undefined in TypeScript, so guard before accessing its fields.
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;
}

Repeated Fields, maps, and Streaming RPCs

Two more building blocks complete most enterprise contracts:

  • repeated T field = N; → a TypeScript array T[]. An empty list and an unset list are indistinguishable on the wire.
  • map<string, T> → a TypeScript record; useful for labels/metadata.

Prefix stream on the request, response, or both to declare server-streaming, client-streaming, or bidirectional RPCs. In NestJS, streaming methods use @GrpcStreamMethod and work with 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;
}

Generating Typed Interfaces with ts-proto

Hand-writing interfaces drifts from the .proto. Use a generator like ts-proto (via protoc) to emit interfaces, encode/decode helpers, and a NestJS-friendly client/service shape that stays in lockstep with the contract.

  • nestJs=true emits the gRPC service/client interfaces NestJS expects.
  • Run it in CI so a stale generated file fails the build, guaranteeing code matches the 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"
  }
}

Quick Check: Evolving the Contract

You shipped Invoice with string customer_id = 2;. A new requirement needs you to stop sending customer_id and instead send a richer Customer customer = 6; nested message. Deployed older clients must keep working.

Recap: Contract-First Protobuf

You can now author a service contract and turn it into typed NestJS interfaces:

  • Structure: syntax = proto3, a package namespace, message shapes, and a service with rpc methods.
  • Field numbers are the wire contract — additive evolution only; reserved retired numbers and names.
  • Type mapping: watch int64 → string, snake_case → camelCase, enums need a *_UNSPECIFIED zero value.
  • Composition: nested messages, repeated arrays, map, and stream RPCs.
  • Generation: drive types from the .proto with ts-proto in CI so code can never drift from the contract.

Sıkça Sorulan Sorular

“Protobuf'ta Hizmetleri ve Mesajları Tanımlama” dersi ücretsiz mi?

Evet — “Protobuf'ta Hizmetleri ve Mesajları Tanımlama” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve NestJS Enterprise Backend APIs kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. NestJS Enterprise Backend APIs kursu toplamda 4 dersten oluşur.

“Protobuf'ta Hizmetleri ve Mesajları Tanımlama” dersinde ne öğreneceğim?

.proto sözleşmeleri oluşturun ve NestJS mikro hizmetleri için türü belirlenmiş arayüzler üretin. NestJS Enterprise Backend APIs ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

NestJS Enterprise Backend APIs öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te NestJS Enterprise Backend APIs, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 1. dersidir.

“Protobuf'ta Hizmetleri ve Mesajları Tanımlama” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu NestJS Enterprise Backend APIs dersinde kod yazıp çalıştırabilir miyim?

Evet. Her NestJS Enterprise Backend APIs dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. Protobuf'ta Hizmetleri ve Mesajları Tanımlama
  2. gRPC Metotlarını Uygulama ve Kullanma
  3. Akış RPC'leri ve Geri Basınç
  4. Sözleşme Gelişimi ve Geriye Dönük Uyumluluk
← NestJS Enterprise Backend APIs Sayfasına Dön