Service Communication: REST and gRPC
Connect services synchronously and efficiently.
Service Communication: REST and gRPC is a free PHP Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the PHP Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
REST and gRPC
Services need to talk synchronously: a request goes out, an answer comes back. The two dominant choices are REST over HTTP/JSON and gRPC over HTTP/2 + Protobuf. They optimize for different things — REST for reach and human-friendliness, gRPC for speed and strict contracts.
This lesson shows both from a PHP perspective and when to pick each.
REST: the Lingua Franca
REST models resources behind URLs and uses HTTP verbs and status codes for semantics. Its strengths: universal tooling, cacheability, debuggability with curl, and zero special client needs. Its weaknesses: verbose JSON, no enforced schema, and request/response only.
For public APIs and browser-facing endpoints, REST is almost always right.
Calling a REST Service
Use a PSR-18 HTTP client (Guzzle here). Always set a connect and request timeout — an unbounded call to a slow peer can exhaust your PHP-FPM workers and cascade the outage.
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$http = new Client([
'base_uri' => 'http://customers-svc/',
'connect_timeout' => 1.0, // never block forever on connect
'timeout' => 3.0, // total request budget
'http_errors' => false,
]);
$res = $http->get('customers/42', ['headers' => ['Accept' => 'application/json']]);
if ($res->getStatusCode() === 200) {
$customer = json_decode((string) $res->getBody(), true);
echo $customer['email'] . "\n";
}Status Codes Are the Contract
In service-to-service REST, HTTP status codes are your error protocol. Treat them deliberately:
2xxsuccess;4xxthe caller's fault (don't retry blindly);5xx/timeouts are retryable.- Use
409for conflicts,422for validation,429for rate limits (respectRetry-After).
Retrying a 400 just wastes calls; retrying a 503 with backoff is correct.
<?php
function isRetryable(int $status): bool {
return $status === 0 // timeout/connection error
|| $status === 429
|| ($status >= 500 && $status !== 501);
}
var_dump(isRetryable(503)); // true
var_dump(isRetryable(400)); // falsegRPC: Contract-First & Fast
gRPC uses Protocol Buffers: you define services and messages in a .proto file, then generate strongly-typed client/server stubs. Over HTTP/2 with binary Protobuf it is far more compact and lower-latency than JSON, and it supports streaming.
syntax = "proto3";
package customers;
service Customers {
rpc GetCustomer (GetCustomerRequest) returns (Customer);
}
message GetCustomerRequest { string id = 1; }
message Customer {
string id = 1;
string email = 2;
int32 loyalty_points = 3;
}Generating PHP Stubs
Install the gRPC PHP extension and the protoc plugin, then generate client classes from the .proto. PHP can act as a fully featured gRPC client via ext-grpc; running a native PHP gRPC server typically needs Roadrunner or Swoole.
pecl install grpc
composer require grpc/grpc google/protobuf
protoc --proto_path=. \
--php_out=./generated \
--grpc_out=./generated \
--plugin=protoc-gen-grpc=$(which grpc_php_plugin) \
customers.protoA gRPC Client Call
Generated stubs give you typed requests and responses. A gRPC call returns the message and a status object — always check the status code before trusting the response.
<?php
require 'vendor/autoload.php';
use Customers\CustomersClient;
use Customers\GetCustomerRequest;
use Grpc\ChannelCredentials;
$client = new CustomersClient('customers-svc:50051', [
'credentials' => ChannelCredentials::createInsecure(),
]);
$req = (new GetCustomerRequest())->setId('42');
[$reply, $status] = $client->GetCustomer($req)->wait();
if ($status->code === \Grpc\STATUS_OK) {
echo $reply->getEmail(), "\n";
} else {
fwrite(STDERR, "gRPC error: {$status->details}\n");
}Schema Evolution
Protobuf is built for forward/backward compatibility — if you respect its rules:
- Never reuse or change a field number. Add new fields with new numbers.
- Mark removed fields
reservedso the number can't be recycled. - Old clients ignore unknown fields; missing fields take type defaults.
JSON/REST gives you none of this for free — you enforce compatibility by convention (and ideally a shared OpenAPI schema with contract tests).
message Customer {
string id = 1;
string email = 2;
reserved 3; // old 'loyalty_points', never reuse 3
reserved "loyalty_points";
string display_name = 4; // new field, safe additive change
}Streaming
gRPC supports four call types; REST natively supports only the first:
- Unary — one request, one response.
- Server streaming — one request, a stream of responses (e.g. live updates).
- Client streaming — a stream of requests, one response (e.g. bulk upload).
- Bidirectional — both stream concurrently.
If your use case is push or long-lived data flow, gRPC streaming beats polling a REST endpoint.
Propagating Context & Deadlines
Synchronous calls form chains, so two things must travel with every request: a correlation/trace id for end-to-end tracing, and a deadline so a slow leaf can't make the whole chain hang. gRPC has first-class deadlines; in REST you emulate them with a shrinking timeout budget passed downstream.
<?php
// REST: shrink the remaining budget as the call chain deepens
function forwardHeaders(array $incoming, float $remainingMs): array {
return [
'X-Correlation-Id' => $incoming['X-Correlation-Id'] ?? bin2hex(random_bytes(8)),
// downstream must finish within what's left of our budget
'X-Timeout-Ms' => (string) max(0, (int) $remainingMs),
];
}
print_r(forwardHeaders(['X-Correlation-Id' => 'trace-9'], 1500));Choosing Between Them
A practical decision guide:
- REST for public/partner APIs, browser clients, simple CRUD, easy debugging, and broad cache support.
- gRPC for internal, high-volume, low-latency service-to-service calls, strict typed contracts, and streaming.
Many systems run both: gRPC behind the gateway between services, REST at the edge for the outside world. Don't force one tool to do the other's job.
Quick Check
Matching protocol to use case.
Recap
Synchronous service communication:
- REST/JSON — universal, debuggable, cacheable; status codes are the contract; always set timeouts.
- gRPC/Protobuf — contract-first, compact, fast, streaming; generate typed PHP stubs.
- Decide retryability from status/gRPC codes; never retry client errors.
- Evolve schemas additively — never reuse Protobuf field numbers.
- REST at the edge, gRPC between internal services is a common, sound split.
Next: routing and locating all these services with gateways and discovery.
Frequently asked questions
Is the “Service Communication: REST and gRPC” lesson free?
Yes — the full text of “Service Communication: REST and gRPC” is free to read here on the web, and the PHP Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the PHP Academy course, upgrade to CoddyKit PRO.
What will I learn in “Service Communication: REST and gRPC”?
Connect services synchronously and efficiently. You practise PHP Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start PHP Academy?
No prior experience is required. PHP Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Service Communication: REST and gRPC” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this PHP Academy lesson?
Yes. Every PHP Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- From Monolith to Microservices
- Service Communication: REST and gRPC
- API Gateways and Service Discovery
- Resilience: Circuit Breakers and Retries