Table of Contents

    RPC and gRPC

    API DESIGN & SERVICE CONTRACTS

    RPC and gRPC

    Learn how Remote Procedure Call models distributed communication as method calls and how gRPC combines typed service contracts, Protocol Buffers, generated client code, HTTP/2 streams, deadlines, metadata and structured status handling.

    Introduction

    Distributed applications frequently need one service to request work from another service. REST models these interactions primarily around resources and HTTP semantics. Remote Procedure Call, commonly abbreviated as RPC, models communication around procedures or methods that can be invoked remotely.

    An RPC client calls a method using parameters. The RPC framework serializes the request, sends it across a network, invokes the corresponding server implementation and returns a result or error.

    RPC systems commonly provide:

    • Service and method definitions
    • Typed request and response messages
    • Serialization and deserialization
    • Generated client and server code
    • Network communication
    • Deadlines and cancellation
    • Structured status handling
    • Authentication metadata
    • Unary and streaming operations

    gRPC is an RPC framework in which a service contract defines remotely callable methods, parameters and return types. gRPC commonly uses Protocol Buffers as both its Interface Definition Language and its binary message format.

    Core idea: RPC makes a remote operation appear similar to a local method call, but the operation still crosses a network. Remote calls can be delayed, duplicated by retry logic, cancelled, rejected or completed after the client stops waiting.

    In your System Design curriculum, RPC and gRPC follows REST in the API Design & Service Contracts module. The module also covers GraphQL, resource modelling, pagination, versioning, idempotency, authentication versus authorization and rate-limit semantics.

    Prerequisites

    # Prerequisite Why It Is Needed
    1 REST and API contracts RPC represents an alternative API interaction model with different trade-offs.
    2 HTTP/2 Standard gRPC communication is carried using HTTP/2 framing.
    3 TLS Production RPC communication requires appropriate transport protection and peer authentication.
    4 Binary serialization gRPC commonly exchanges Protocol Buffer messages rather than human-readable JSON.
    5 Timeouts and retries Remote method calls can fail or produce uncertain outcomes.
    6 Authentication and authorization Every protected RPC method requires identity and permission controls.

    What Is RPC?

    Remote Procedure Call is a communication model in which a client invokes a procedure implemented by another process or service.

    RPC Call
    client method call → serialize request → network transfer → execute server method → serialize response → return result

    Simplified Architecture

    Client Application
            |
            | Calls client stub
            v
    Generated Client Stub
            |
            | Serializes request
            v
    RPC Transport
            |
            | Network communication
            v
    RPC Server
            |
            | Deserializes request
            v
    Service Implementation
            |
            | Produces response
            v
    Generated Server Code
            |
            | Serializes response
            v
    Client receives result

    Local Call vs Remote Call

    Area Local Method Call Remote Procedure Call
    Execution Occurs in the local process Occurs in another process or service
    Communication Uses local memory and runtime mechanisms Uses serialization and network communication
    Latency Normally low and predictable relative to networking Includes network, queueing and remote processing time
    Failure Returns a result or local exception Can fail because of timeout, connection loss, server failure or protocol errors
    Completion certainty Usually observable within the process The server can complete after the client stops waiting
    Data transfer Passes local values or references Transfers serialized values

    Distributed-systems rule: Do not design a remote call as if it were a reliable local function. Every remote call needs a deadline, error contract, cancellation policy and retry decision.

    REST vs RPC

    Area REST-oriented API RPC-oriented API
    Primary abstraction Resources and representations Services and methods
    Operation expression HTTP methods applied to resource URIs Named remote procedures
    Example POST /orders CreateOrder()
    Contract HTTP semantics plus an API description Service interface with typed messages
    Common representation JSON Protocol Buffers in gRPC
    Browser accessibility Works naturally with browser HTTP APIs Standard browser use normally requires a compatible bridge such as gRPC-Web
    Streaming Possible through HTTP streaming mechanisms Defined as part of gRPC method types
    Human readability JSON requests are easy to inspect manually Binary messages usually require schema-aware tools

    What Is gRPC?

    gRPC is a framework for defining services and invoking their methods across process and network boundaries.

    A gRPC design commonly includes:

    • A .proto contract file
    • Service definitions
    • RPC method definitions
    • Protocol Buffer message schemas
    • Generated client stubs
    • Generated server interfaces
    • HTTP/2-based transport
    • gRPC metadata and status codes
    .proto contract
          |
          v
    Protocol Buffer compiler
          |
          +--> Generated client code
          |
          +--> Generated server code
          |
          +--> Generated message classes

    Protocol Buffers

    Protocol Buffers provide a language-neutral mechanism for defining and serializing structured data.

    A Protocol Buffer contract defines:

    • Messages
    • Fields
    • Field types
    • Stable numeric field identifiers
    • Enumerations
    • Services
    • RPC methods

    Basic Message Definition

    syntax = "proto3";
    
    package customer.v1;
    
    message Customer {
      int64 id = 1;
      string name = 2;
      string email = 3;
      CustomerStatus status = 4;
    }
    
    enum CustomerStatus {
      CUSTOMER_STATUS_UNSPECIFIED = 0;
      CUSTOMER_STATUS_ACTIVE = 1;
      CUSTOMER_STATUS_INACTIVE = 2;
    }

    The field numbers are part of the binary contract. They identify fields in serialized data and must be managed carefully during schema evolution.

    Defining a gRPC Service

    syntax = "proto3";
    
    package customer.v1;
    
    service CustomerService {
      rpc GetCustomer(
        GetCustomerRequest
      ) returns (
        GetCustomerResponse
      );
    
      rpc CreateCustomer(
        CreateCustomerRequest
      ) returns (
        CreateCustomerResponse
      );
    
      rpc UpdateCustomer(
        UpdateCustomerRequest
      ) returns (
        UpdateCustomerResponse
      );
    
      rpc DeleteCustomer(
        DeleteCustomerRequest
      ) returns (
        DeleteCustomerResponse
      );
    }
    
    message GetCustomerRequest {
      int64 customer_id = 1;
    }
    
    message GetCustomerResponse {
      Customer customer = 1;
    }
    
    message CreateCustomerRequest {
      string name = 1;
      string email = 2;
      string idempotency_key = 3;
    }
    
    message CreateCustomerResponse {
      Customer customer = 1;
    }
    
    message UpdateCustomerRequest {
      int64 customer_id = 1;
      string name = 2;
      string email = 3;
      int64 expected_version = 4;
    }
    
    message UpdateCustomerResponse {
      Customer customer = 1;
    }
    
    message DeleteCustomerRequest {
      int64 customer_id = 1;
    }
    
    message DeleteCustomerResponse {
    }

    The contract identifies remotely callable methods and the request and response types associated with every call.

    Code Generation

    The Protocol Buffer compiler and gRPC plugins generate language-specific code from the service contract.

    protoc \
      --proto_path=./proto \
      --php_out=./generated \
      --grpc_out=./generated \
      --plugin=protoc-gen-grpc=/path/to/grpc_php_plugin \
      ./proto/customer/v1/customer_service.proto

    Exact compiler options and plugins depend on the selected language, framework version and build environment.

    Generated code can include:

    • Request and response message classes
    • Serialization and parsing logic
    • Client stub methods
    • Server-side service interfaces
    • Type-safe accessors

    gRPC over HTTP/2

    Standard gRPC calls are carried through HTTP/2 framing. A gRPC request uses HTTP/2 headers and one or more length-prefixed messages.

    gRPC Request
    
    HTTP/2 request headers
            |
            v
    Length-prefixed request message
            |
            v
    End of request stream
    
    
    gRPC Response
    
    HTTP/2 response headers
            |
            v
    Length-prefixed response message
            |
            v
    gRPC trailers with final status

    gRPC uses HTTP/2 capabilities such as multiplexed streams and long-lived connections while defining its own method, message and status conventions.

    Length-prefixed Messages

    +--------------------+----------------------+------------------+
    | Compression Flag   | Message Length       | Serialized Data  |
    | 1 byte             | 4 bytes              | N bytes          |
    +--------------------+----------------------+------------------+

    Each message identifies whether message compression is applied and carries the size of the serialized message body.

    gRPC Call Types

    Call Type Request Pattern Response Pattern
    Unary RPC One request One response
    Server-streaming RPC One request Stream of responses
    Client-streaming RPC Stream of requests One response
    Bidirectional-streaming RPC Stream of requests Stream of responses

    Unary RPC

    rpc GetCustomer(
      GetCustomerRequest
    ) returns (
      GetCustomerResponse
    );
    Client sends one request
            |
            v
    Server performs operation
            |
            v
    Server returns one response

    Unary RPC resembles a traditional request-response method call.

    Server-streaming RPC

    rpc WatchOrder(
      WatchOrderRequest
    ) returns (
      stream OrderUpdate
    );
    Client sends one request
            |
            v
    Server sends update 1
            |
            v
    Server sends update 2
            |
            v
    Server sends update 3
            |
            v
    Server completes response stream

    This is useful for:

    • Progress updates
    • Monitoring events
    • Change notifications
    • Large result streams

    Client-streaming RPC

    rpc UploadMeasurements(
      stream Measurement
    ) returns (
      UploadSummary
    );
    Client sends message 1
    Client sends message 2
    Client sends message 3
    Client completes request stream
            |
            v
    Server returns one summary response

    This is useful for:

    • Batch uploads
    • Telemetry submission
    • Incremental file processing
    • Aggregating client events

    Bidirectional Streaming

    rpc Collaborate(
      stream CollaborationCommand
    ) returns (
      stream CollaborationEvent
    );
    Client                                    Server
      |                                          |
      | Request message 1                        |
      |----------------------------------------->|
      |                                          |
      | Response message 1                       |
      |<-----------------------------------------|
      |                                          |
      | Response message 2                       |
      |<-----------------------------------------|
      |                                          |
      | Request message 2                        |
      |----------------------------------------->|
      |                                          |
      | Independent message flow                 |
      |<========================================>|

    Request and response streams operate independently. The application protocol must define message correlation, ordering, completion, acknowledgements and error behaviour.

    Deadlines

    Every remote call should use a finite deadline. A deadline defines how long the client is willing to wait for the complete operation.

    Client starts RPC
          |
          v
    Deadline begins
          |
          +--> Response arrives before deadline:
          |       return result
          |
          +--> Deadline expires:
                  cancel local wait
                  propagate cancellation where supported
                  return deadline error

    Uncertain outcome: A client deadline expiring does not prove that the server made no change. The server might have committed the operation before cancellation was observed.

    A deadline should account for:

    • Connection establishment
    • TLS negotiation
    • Queueing
    • Server processing
    • Downstream calls
    • Response transfer

    Cancellation

    Cancellation communicates that the caller no longer needs the operation. Server implementations should observe the cancellation context and stop unnecessary work when safe.

    Client cancels call
            |
            v
    gRPC runtime communicates cancellation
            |
            v
    Server observes cancellation
            |
            +--> Work can stop safely:
            |       release resources
            |
            +--> Operation already committed:
                    preserve committed outcome
                    avoid unsafe rollback assumptions

    Cancellation is cooperative. It does not guarantee that the remote operation was never started or completed.

    Retries

    A failed RPC can be retried only when the method contract and failure state make repetition safe.

    RPC fails or times out
            |
            v
    Can the operation be safely repeated?
            |
            +--> No:
            |       return uncertain outcome
            |
            +--> Yes:
                    apply bounded retry
                    with backoff and jitter

    Retry design should define:

    • Retryable status codes
    • Maximum attempts
    • Backoff policy
    • Randomized jitter
    • Complete operation deadline
    • Idempotency requirements
    • Retry ownership

    Idempotency

    Read operations such as GetCustomer can naturally support safe repetition. Creation, payment and workflow commands require explicit idempotency design.

    message CreateOrderRequest {
      string idempotency_key = 1;
      int64 customer_id = 2;
      repeated OrderLine items = 3;
    }
    First call with key K:
    
    Validate key
    Create order
    Store result for key K
    Return order
    
    
    Retry with key K and identical request:
    
    Find stored result
    Do not create another order
    Return original result
    
    
    Key K with different request:
    
    Reject as a conflict

    gRPC Status Codes

    gRPC returns a structured status containing a status code and optional error information.

    Status Typical Meaning
    OK The operation completed successfully
    CANCELLED The operation was cancelled
    UNKNOWN An unknown error occurred
    INVALID_ARGUMENT The request contains invalid arguments
    DEADLINE_EXCEEDED The operation did not complete before its deadline
    NOT_FOUND The requested entity was not found
    ALREADY_EXISTS An entity that the caller attempted to create already exists
    PERMISSION_DENIED The caller lacks permission for the operation
    UNAUTHENTICATED Valid authentication credentials are missing
    RESOURCE_EXHAUSTED An applicable quota or capacity limit was exceeded
    FAILED_PRECONDITION The system is not in a state required for the operation
    ABORTED The operation was aborted because of a conflict
    OUT_OF_RANGE The requested operation is outside an allowed range
    UNIMPLEMENTED The operation is unsupported or not implemented
    INTERNAL An internal invariant or processing failure occurred
    UNAVAILABLE The service is temporarily unavailable
    DATA_LOSS Unrecoverable data loss or corruption was detected

    Error Contract

    A service should return stable machine-readable error information without exposing internal stack traces, SQL statements or infrastructure details.

    {
        "code": "INVALID_ARGUMENT",
        "message": "Request validation failed.",
        "details": [
            {
                "field": "email",
                "reason": "invalid_format"
            }
        ],
        "traceId": "trace-8f21"
    }

    An error contract should distinguish:

    • Client validation errors
    • Authentication failures
    • Authorization failures
    • Missing entities
    • State conflicts
    • Deadline expiration
    • Temporary service unavailability
    • Unexpected internal failures

    Metadata

    gRPC metadata carries additional call information using HTTP/2 fields.

    Metadata can carry:

    • Authentication credentials
    • Correlation identifiers
    • Tracing context
    • Locale preferences
    • Client-version information
    • Application-specific request context
    authorization: Bearer ACCESS_TOKEN
    x-correlation-id: request-1042
    traceparent: trace-context-value
    accept-language: en-US

    Metadata rule: Metadata is part of the request contract and must be validated, size-limited and protected. Credentials and sensitive metadata must not be written to ordinary logs.

    Authentication

    Authentication establishes the identity of the calling service, user or workload.

    Common approaches include:

    • TLS server authentication
    • Mutual TLS
    • Bearer access tokens
    • Signed workload credentials
    • Service-mesh identity
    Client establishes protected connection
            |
            v
    Client presents credential
            |
            v
    Server validates credential
            |
            v
    Caller identity is established
            |
            v
    Method authorization is evaluated

    Authorization

    Every protected method requires an authorization decision. Authorization should consider both the method and the target entity.

    Authenticated caller
            |
            v
    Calls GetCustomer(customer_id = 42)
            |
            v
    Load customer 42
            |
            v
    Evaluate permission for customer 42
            |
            +--> Allowed:
            |       return customer
            |
            +--> Denied:
                    return permission error

    Do not authorize access only because the request contains a syntactically valid entity identifier.

    TLS and Mutual TLS

    gRPC connections should use TLS when communication requires protected transport. Mutual TLS additionally validates client certificates.

    Server-authenticated TLS:
    
    Client validates server certificate.
    
    
    Mutual TLS:
    
    Client validates server certificate.
    Server validates client certificate.

    Certificate identity establishes an authenticated context. Business authorization remains a separate service decision.

    Flow Control and Backpressure

    Streaming methods need backpressure so a fast producer cannot create unlimited buffered data for a slow consumer.

    Fast producer
          |
          v
    Bounded application queue
          |
          v
    gRPC and HTTP/2 flow control
          |
          v
    Slow consumer

    A streaming contract should define:

    • Maximum message size
    • Maximum queued messages
    • Maximum queued bytes
    • Consumer cancellation behaviour
    • Producer waiting behaviour
    • Whether data can be coalesced or discarded

    Message-size Limits

    Every incoming and outgoing message should have explicit size limits.

    Unbounded messages can cause:

    • Memory exhaustion
    • Long serialization pauses
    • High network latency
    • Slow garbage collection
    • Resource-exhaustion attacks

    Large datasets should normally be paginated, streamed or transferred through a purpose-built storage and download mechanism.

    Protocol Buffer Compatibility

    Protocol Buffer contracts should evolve without changing the meaning of existing field numbers.

    Compatible Additive Change

    message Customer {
      int64 id = 1;
      string name = 2;
      string email = 3;
    
      string preferred_language = 4;
    }

    Do Not Reuse Removed Field Numbers

    message Customer {
      int64 id = 1;
      string name = 2;
    
      reserved 3;
      reserved "email";
    }

    Reserving removed numbers and names prevents accidental reuse that could cause old and new clients to interpret data differently.

    Field-number Rules

    Schema Evolution Practices

    • Never change the meaning of an existing field number.
    • Do not reuse a deleted field number.
    • Reserve deleted field numbers and names.
    • Add new fields using new numbers.
    • Avoid changing an existing field to an incompatible type.
    • Design default-value behaviour carefully.
    • Include an unspecified zero value in enumerations.
    • Do not assume every client upgrades at the same time.
    • Run compatibility checks in the build pipeline.

    Field Presence

    APIs must distinguish when necessary between:

    • A field that was not sent
    • A field sent with its default value
    • A field explicitly cleared
    • A field inherited from existing state
    message UpdateCustomerRequest {
      int64 customer_id = 1;
      optional string name = 2;
      optional string email = 3;
    }

    Presence-aware fields help prevent partial-update APIs from treating an omitted value as an instruction to clear existing data.

    Field Masks

    Field masks can identify fields that a caller intends to update.

    import "google/protobuf/field_mask.proto";
    
    message UpdateCustomerRequest {
      Customer customer = 1;
      google.protobuf.FieldMask update_mask = 2;
      int64 expected_version = 3;
    }
    Customer values:
    
    name = "Updated Name"
    email = "new@example.com"
    
    
    Update mask:
    
    paths:
    - name
    
    
    Result:
    
    Only name is changed.
    Email retains its existing value.

    Optimistic Concurrency

    message UpdateCustomerRequest {
      Customer customer = 1;
      int64 expected_version = 2;
    }
    Client reads:
    
    customer version = 7
    
    
    Client submits update:
    
    expected_version = 7
    
    
    Server verifies:
    
    Current version is 7:
    Apply update and create version 8.
    
    Current version is not 7:
    Reject the stale update.

    Version checking prevents one caller from unknowingly overwriting changes made by another caller.

    Health Checking

    A production gRPC service should expose health information through an appropriate health-checking contract.

    Health checks can distinguish:

    • Process liveness
    • Service readiness
    • Serving status
    • Dependency degradation

    A healthy process does not prove that every method and dependency is ready for production traffic.

    Server Reflection

    Server reflection can allow compatible tools to discover available gRPC services and descriptors at runtime.

    Reflection is useful for authorized development and diagnostic tooling, but production exposure should follow the service's security and information- disclosure policy.

    Load Balancing

    gRPC commonly reuses long-lived HTTP/2 connections. Connection reuse affects how traffic is distributed across backend instances.

    Client
      |
      | Long-lived HTTP/2 connection
      v
    Load Balancer
      |
      v
    Backend A
    
    
    Without suitable balancing design:
    
    Many RPC calls on that connection
    can continue reaching Backend A.

    A balancing design can consider:

    • Client-side load balancing
    • Proxy-based load balancing
    • Name resolution
    • Health checking
    • Connection lifetime
    • Backend draining
    • Retry and failover policy

    Graceful Shutdown

    Deployment begins
          |
          v
    Stop accepting new calls
          |
          v
    Mark instance not ready
          |
          v
    Allow in-flight calls to finish
          |
          v
    Cancel calls after shutdown deadline
          |
          v
    Close connections and stop process

    Streaming calls require a defined drain, cancellation and reconnection policy.

    Browser Compatibility

    Standard browser APIs do not generally expose the complete gRPC HTTP/2 protocol directly. Browser applications commonly use gRPC-Web or a compatible gateway.

    Browser
       |
       | gRPC-Web request
       v
    gRPC-Web Proxy or Gateway
       |
       | Standard gRPC
       v
    gRPC Backend Service

    The gateway becomes part of the contract and must handle authentication, CORS, translation, limits, errors and observability correctly.

    REST Gateway

    Some architectures expose REST or JSON externally while using gRPC between backend services.

    External Client
          |
          | REST and JSON
          v
    API Gateway
          |
          | Translates request
          v
    Internal gRPC Service

    The translation contract should define:

    • HTTP method and URI mapping
    • JSON-to-Protobuf conversion
    • Status-code mapping
    • Error-detail mapping
    • Authentication propagation
    • Deadline propagation
    • Streaming limitations

    Interceptors

    Interceptors can apply cross-cutting logic around client or server calls.

    Common interceptor responsibilities include:

    • Authentication
    • Authorization context
    • Correlation identifiers
    • Tracing
    • Metrics
    • Structured logging
    • Retry policy
    • Validation

    Interceptor rule: Cross-cutting middleware should not hide method-specific authorization, validation or idempotency requirements.

    Observability

    Useful gRPC telemetry includes:

    • Calls per method
    • Latency percentiles per method
    • Status-code distribution
    • Deadline-exceeded count
    • Cancellation count
    • Retry count
    • Request and response message sizes
    • Active streaming calls
    • Messages per stream
    • Authentication and authorization failures
    • Backend connection state
    • Queue depth and backpressure

    Logs should identify the method, status, duration and trace context without recording credentials or sensitive message contents.

    Test with grpcurl

    List Available Services

    grpcurl \
      api.example.com:443 \
      list

    Describe a Service

    grpcurl \
      api.example.com:443 \
      describe customer.v1.CustomerService

    Invoke a Unary Method

    grpcurl \
      -H 'authorization: Bearer ACCESS_TOKEN' \
      -d '{"customerId":"42"}' \
      api.example.com:443 \
      customer.v1.CustomerService/GetCustomer

    Listing and describing services require server reflection or locally supplied descriptors. Do not place production credentials directly in shell history.

    Inspect HTTP/2 Connections

    ss -tnp
    openssl s_client \
      -connect api.example.com:443 \
      -servername api.example.com \
      -alpn h2

    These commands can confirm transport connections and ALPN negotiation, but a gRPC-aware client is required to validate method-level behaviour.

    Troubleshooting Workflow

    Troubleshooting Flow
    confirm service and method → check DNS and transport → inspect TLS → validate metadata → inspect gRPC status → trace dependencies
    1. Confirm the package, service and method names.
    2. Confirm the deployed contract version.
    3. Resolve the server name and verify routing.
    4. Confirm TCP and TLS connectivity.
    5. Confirm HTTP/2 negotiation.
    6. Inspect authentication metadata.
    7. Record the gRPC status code and safe error details.
    8. Check the call deadline and cancellation state.
    9. Inspect message-size and flow-control limits.
    10. Check retries and idempotency handling.
    11. Use the trace identifier to inspect downstream calls.
    12. Compare runtime behaviour with the deployed .proto contract.

    Common RPC and gRPC Mistakes

    1

    Treating a Remote Call as a Local Function

    Remote calls have network latency, partial failures, cancellation and uncertain outcomes.

    2

    Using Infinite Deadlines

    Calls can retain threads, connections and downstream resources indefinitely.

    3

    Retrying Every Failure

    Some failures are permanent, and some methods can create duplicate business effects.

    4

    Reusing Protocol Buffer Field Numbers

    Old and new clients can interpret the same serialized field differently.

    5

    Changing Field Types Incompatibly

    Generated clients and stored messages can become incompatible with the changed schema.

    6

    Sending Large Unary Messages

    Large messages increase serialization, memory, transport and retry costs. Use pagination, streaming or object storage where appropriate.

    7

    Using Streaming without Backpressure

    A fast producer can create unbounded buffers for a slow consumer.

    8

    Ignoring Cancellation

    The server can continue expensive work after the caller no longer needs the result.

    9

    Logging Complete Metadata

    Metadata can contain access credentials, identity information and tracing values that require protection.

    10

    Assuming Authentication Grants Every Method

    Every method and target entity requires an authorization decision.

    11

    Using One Long-lived Connection without Balancing Awareness

    Connection reuse can concentrate calls on one backend unless the balancing architecture accounts for gRPC connection behaviour.

    12

    Publishing a Contract without Compatibility Tests

    Schema checks and integration tests should verify that old and new clients remain compatible according to policy.

    Recommended Test Cases

    Test Expected Evidence
    Valid unary call The expected typed response and OK status are returned
    Invalid request The method returns a structured validation error
    Unauthenticated call The call is rejected without executing protected work
    Unauthorized entity The caller cannot access another tenant's or user's entity
    Deadline expiration The call ends within the configured deadline
    Cancellation The server stops unnecessary work when cancellation is observed
    Duplicate create retry The idempotency contract prevents duplicate effects
    Stale update The expected-version check rejects the conflicting request
    Oversized message The message is rejected without uncontrolled memory growth
    Slow stream consumer The backpressure and queue policy is applied
    Schema compatibility Old and new clients interpret supported messages correctly
    Backend shutdown Calls drain, fail over or return controlled statuses according to policy

    RPC and gRPC Best Practices

    Recommended Practices

    • Design every remote call as a fallible network operation.
    • Define typed request and response contracts.
    • Use finite deadlines on every call.
    • Propagate deadlines to downstream calls.
    • Observe cancellation and release resources promptly.
    • Retry only documented transient failures.
    • Use idempotency protection for retryable state-changing methods.
    • Use bounded retries with exponential backoff and jitter.
    • Apply request, response and stream message-size limits.
    • Use bounded application queues and backpressure.
    • Authenticate every protected connection or call.
    • Authorize every method and target entity.
    • Use TLS and mTLS according to the trust model.
    • Never reuse removed Protocol Buffer field numbers.
    • Reserve deleted fields and names.
    • Prefer additive schema evolution.
    • Monitor methods, statuses, deadlines, retries and stream counts.
    • Drain long-lived calls during deployments.
    • Test generated clients across supported languages.
    • Keep the deployed implementation aligned with the published contract.

    Practice Exercise

    Design a gRPC service for customer and order operations and compare it with the earlier REST API.

    Requirements

    1. Define versioned package names.
    2. Define customer and order messages.
    3. Implement a unary customer lookup.
    4. Implement idempotent order creation.
    5. Implement a server stream for order-status updates.
    6. Implement a client stream for telemetry upload.
    7. Apply finite deadlines.
    8. Propagate cancellation to database and downstream operations.
    9. Authenticate callers through protected metadata or mTLS.
    10. Authorize every customer and order operation.
    11. Apply request and response message-size limits.
    12. Use expected versions for updates.
    13. Return structured gRPC statuses.
    14. Expose an authorized health-check service.
    15. Add compatibility tests for the .proto contract.

    Suggested Service Contract

    syntax = "proto3";
    
    package order.v1;
    
    service OrderService {
      rpc GetOrder(
        GetOrderRequest
      ) returns (
        GetOrderResponse
      );
    
      rpc CreateOrder(
        CreateOrderRequest
      ) returns (
        CreateOrderResponse
      );
    
      rpc WatchOrder(
        WatchOrderRequest
      ) returns (
        stream OrderUpdate
      );
    }
    
    message GetOrderRequest {
      int64 order_id = 1;
    }
    
    message GetOrderResponse {
      Order order = 1;
    }
    
    message CreateOrderRequest {
      string idempotency_key = 1;
      int64 customer_id = 2;
      repeated OrderLine lines = 3;
    }
    
    message CreateOrderResponse {
      Order order = 1;
    }
    
    message WatchOrderRequest {
      int64 order_id = 1;
      int64 after_version = 2;
    }
    
    message OrderUpdate {
      int64 order_id = 1;
      int64 version = 2;
      OrderStatus status = 3;
      string occurred_at = 4;
    }
    
    message OrderLine {
      string product_id = 1;
      int32 quantity = 2;
    }
    
    message Order {
      int64 id = 1;
      int64 customer_id = 2;
      repeated OrderLine lines = 3;
      OrderStatus status = 4;
      int64 version = 5;
    }
    
    enum OrderStatus {
      ORDER_STATUS_UNSPECIFIED = 0;
      ORDER_STATUS_PENDING = 1;
      ORDER_STATUS_CONFIRMED = 2;
      ORDER_STATUS_PROCESSING = 3;
      ORDER_STATUS_COMPLETED = 4;
      ORDER_STATUS_CANCELLED = 5;
    }

    Frequently Asked Questions

    1

    What is RPC?

    RPC is a communication model in which a client invokes a procedure implemented by another process or service.

    2

    What is gRPC?

    gRPC is an RPC framework based on service definitions, typed messages, generated code and an HTTP/2-based protocol.

    3

    What are Protocol Buffers?

    Protocol Buffers provide a language-neutral mechanism for defining and serializing structured messages.

    4

    Does gRPC require Protocol Buffers?

    Protocol Buffers are the default gRPC interface-definition and message format, although gRPC can support other formats through compatible implementations.

    5

    What are the four gRPC call types?

    The four types are unary, server streaming, client streaming and bidirectional streaming.

    6

    Why does every RPC need a deadline?

    Without a deadline, a failed or stalled dependency can retain client, server and downstream resources indefinitely.

    7

    Does cancellation guarantee that the operation did not complete?

    No. The server can complete or commit an operation before observing the cancellation.

    8

    Can every failed gRPC call be retried?

    No. Retry only when the status and method contract make repetition safe.

    9

    Why should Protocol Buffer field numbers not be reused?

    Reuse can cause old and new clients to interpret the same serialized data as different fields.

    10

    Can browsers call standard gRPC directly?

    Browser applications commonly require gRPC-Web or a compatible gateway rather than using the complete standard gRPC HTTP/2 protocol directly.

    11

    When is gRPC a good choice?

    gRPC is well suited to typed service-to-service APIs, polyglot backend systems and applications requiring unary or streaming method contracts.

    12

    What comes after RPC and gRPC?

    The next topic is GraphQL, followed by resource modelling and pagination.

    Key Takeaway

    RPC models distributed communication as remote method calls, while gRPC combines typed service definitions, Protocol Buffer messages, generated client and server code and HTTP/2 communication. gRPC supports unary, server-streaming, client-streaming and bidirectional-streaming calls. Production contracts must define deadlines, cancellation, status codes, retries, idempotency, authentication, authorization, message limits, backpressure and schema compatibility. A generated stub makes calling a remote method convenient, but the call remains a fallible distributed operation.