gRPC vs GraphQL vs REST vs tRPC 2026 - Chọn Đúng Protocol Giao Tiếp cho Microservices và Frontend-Backend Contract
Posted on: 4/16/2026 12:12:20 PM
Table of contents
- 1. Chọn protocol giao tiếp năm 2026 — một quyết định kiến trúc, không phải sở thích
- 2. Biên niên sử API — vì sao đến 2026 vẫn còn bốn ông lớn
- 3. REST + OpenAPI 3.1 — sự hồi sinh nhờ schema-first
- 4. gRPC, Connect và Protobuf Editions — ngôn ngữ của tầng service-to-service
- 5. GraphQL Federation v2 và Apollo Router — BFF ở quy mô công ty
- 6. tRPC v11 — không schema, không codegen, chỉ có TypeScript
- 7. So sánh trực tiếp — một bảng gói gọn quyết định
- 8. Ma trận quyết định — chọn theo bối cảnh
- 9. Benchmark và con số thực tế
- 10. Contract evolution — nơi nhiều team vấp ngã nhất
- 11. Authentication, authorization, observability — xương sống phải có dù chọn gì
- 12. Ví dụ kiến trúc thực tế — e-commerce đa protocol
- 13. Những pitfall phải tránh khi migrate
- 14. Định hướng — đặt protocol trong chiến lược API của tổ chức
- 15. Tài liệu tham khảo
1. Chọn protocol giao tiếp năm 2026 — một quyết định kiến trúc, không phải sở thích
Mỗi lần mình review kiến trúc cho một nhóm microservices mới, câu hỏi lặp lại nhiều nhất vẫn là: "team nên dùng REST, gRPC, GraphQL hay tRPC?". Câu trả lời "tuỳ" nghe thì đúng, nhưng bỏ qua ba năm gần đây bản thân mỗi protocol đã thay đổi rất nhiều: REST có OpenAPI 3.1 + JSON Schema 2020-12, gRPC đã bước sang Protobuf Editions và Connect-RPC tương thích HTTP/JSON, GraphQL có Federation v2 với Apollo Router viết bằng Rust, còn tRPC v11 đã trở thành chuẩn de-facto cho full-stack TypeScript. Năm 2026 không còn là "REST vs GraphQL" như năm 2018 — mà là một lưới trade-off đa chiều, phụ thuộc vào biên (edge), tầng (service-to-service), client (web/mobile/máy chủ) và hợp đồng (contract evolution) mà hệ thống phải sống chung.
Bài viết này so sánh bốn protocol phổ biến nhất cho backend API năm 2026 dưới ba góc nhìn: hợp đồng và schema evolution, mô hình truyền tải (request/response, streaming, subscription), và chi phí vận hành (latency, payload size, observability). Mình sẽ đi sâu vào những tính năng mới của từng nhóm, đưa ra benchmark thực tế từ các bài so sánh công khai, và quan trọng nhất là dựng sẵn một ma trận quyết định để bạn có thể bê về team mà không cần sa lầy vào tranh cãi tôn giáo nữa.
2. Biên niên sử API — vì sao đến 2026 vẫn còn bốn ông lớn
Để trả lời câu hỏi "chọn gì", cần nhìn lại mỗi protocol sinh ra để giải bài toán gì. Lịch sử không phải để hoài niệm, mà để thấy ràng buộc thiết kế nào còn đúng và ràng buộc nào đã lỗi thời.
3. REST + OpenAPI 3.1 — sự hồi sinh nhờ schema-first
REST thường bị xem là "cũ", nhưng phiên bản REST năm 2026 khác xa REST 2016. Khác biệt chính nằm ở OpenAPI 3.1: spec này hoà hoàn toàn với JSON Schema 2020-12, cho phép mô tả discriminator polymorphism, nullability, const, oneOf/allOf một cách chặt chẽ, và hỗ trợ webhook ở cấp first-class thay vì phải patch ngoài như trước.
Điểm mạnh lớn nhất của REST + OpenAPI hiện nay là hệ sinh thái công cụ: mọi API gateway (AWS API Gateway, Azure API Management, Kong, Envoy, YARP) đều hiểu OpenAPI, mọi ngôn ngữ đều có codegen (NSwag cho .NET, openapi-typescript cho TS, oapi-codegen cho Go, orval/kiota cho client SDK), mọi docs generator đều render được (Redoc, Scalar, Stoplight). Khi cần public API cho đối tác B2B hay xây dựng SDK cho nhiều ngôn ngữ, REST + OpenAPI là lựa chọn ít rủi ro nhất.
OpenAPI 3.1 cải tiến lớn nhất
Hoà với JSON Schema 2020-12 có nghĩa là schema OpenAPI có thể dùng trực tiếp với Ajv, Zod (qua zod-to-json-schema), FluentValidation (qua bộ converter của Microsoft), hoặc Pydantic 2. Một schema, nhiều nơi validate — giảm đáng kể drift giữa API doc và validator thực tế.
Ở phía .NET 10, ASP.NET Core đã tích hợp OpenAPI 3.1 mặc định với package Microsoft.AspNetCore.OpenApi. Dưới đây là một Minimal API tiêu chuẩn năm 2026:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi("v1", opt =>
{
opt.AddDocumentTransformer((doc, ctx, ct) =>
{
doc.Info.Title = "Catalog API";
doc.Info.Version = "v1";
return Task.CompletedTask;
});
});
builder.Services.AddProblemDetails();
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/products/{id:guid}", async (Guid id, ICatalogStore store, CancellationToken ct) =>
{
var product = await store.FindAsync(id, ct);
return product is null
? Results.Problem(statusCode: 404, title: "Product not found")
: Results.Ok(product);
})
.WithName("GetProductById")
.Produces<ProductDto>(200)
.ProducesProblem(404);
app.Run();Điểm đáng lưu ý: ProblemDetails (RFC 9457) đã thành chuẩn lỗi mặc định cho REST 2026. Thay vì trả JSON tự chế, mọi lỗi 4xx/5xx đều nên tuân theo schema application/problem+json — giúp client xử lý lỗi nhất quán qua nhiều service.
3.1. Điểm mạnh và điểm yếu của REST năm 2026
- Mạnh: universal — mọi CDN, WAF, caching layer, browser dev tool đều hiểu. Cacheability qua HTTP header là trời phú. OpenAPI 3.1 chặt về schema. Biểu diễn resource rõ ràng, dễ debug bằng curl.
- Mạnh: HTTP status code mang ý nghĩa ngữ nghĩa; CDN/WAF/proxy sử dụng được ngay — gRPC không có lợi thế này.
- Yếu: không có chuẩn binary — JSON parse/serialize là cost lớn ở scale cao. MessagePack/CBOR tồn tại nhưng hiếm khi được tooling hỗ trợ trọn vẹn.
- Yếu: streaming yếu. SSE và chunked transfer có thể làm, nhưng không có abstraction cấp framework như gRPC streaming.
- Yếu: contract evolution thủ công — phải tự đặt versioning (URI, header, hoặc media type), không có tooling tự phát hiện breaking change mạnh như buf breaking.
4. gRPC, Connect và Protobuf Editions — ngôn ngữ của tầng service-to-service
gRPC không phải protocol duy nhất dùng Protobuf, nhưng là phổ biến nhất. Năm 2026 có hai thay đổi lớn: Protobuf Editions thay thế proto2/proto3, và Connect RPC trở thành cách tiếp cận "gRPC không đau" cho trình duyệt và service không chịu nổi HTTP/2 gRPC thuần.
4.1. Protobuf Editions — chấm dứt chia đôi proto2/proto3
Proto2 có presence rõ ràng (biết field có được set hay không) nhưng cú pháp rối. Proto3 gọn hơn nhưng default value bị conflate với "unset", gây bug tinh vi. Editions thống nhất cả hai qua feature set: mỗi file khai báo edition = "2024", feature như features.field_presence có thể đổi giữa IMPLICIT, EXPLICIT, LEGACY_REQUIRED. Migration từ proto3 sang Editions tự động qua protoc --edition_defaults.
edition = "2024";
package catalog.v1;
import "google/protobuf/timestamp.proto";
option features.field_presence = EXPLICIT;
message Product {
string id = 1;
string name = 2;
int64 price_minor_units = 3;
google.protobuf.Timestamp created_at = 4;
Status status = 5;
enum Status {
STATUS_UNSPECIFIED = 0;
STATUS_DRAFT = 1;
STATUS_PUBLISHED = 2;
STATUS_ARCHIVED = 3;
}
}
service CatalogService {
rpc GetProduct(GetProductRequest) returns (Product);
rpc ListProducts(ListProductsRequest) returns (stream Product);
rpc UploadMedia(stream UploadMediaChunk) returns (UploadMediaResponse);
}4.2. Connect RPC — gRPC không cần HTTP/2
Buf Technologies phát hành Connect năm 2023 và đến 2026 đã thành lựa chọn mặc định cho nhiều team. Connect dùng cùng file .proto, cùng codegen tool, nhưng tạo ra client và server hiểu được ba transport: gRPC thuần (HTTP/2), gRPC-Web (tương thích trình duyệt), và Connect (HTTP/1.1 hoặc HTTP/2 với JSON/Protobuf payload). Điều này cho phép cùng một service phục vụ cả microservice nội bộ lẫn frontend web mà không cần envoy-based proxy chuyển đổi như xưa.
graph LR
subgraph Client["Client layer"]
B["Browser"]
M["Mobile"]
S["Service"]
end
subgraph Transport["Transport"]
C1["Connect JSON HTTP/1.1"]
C2["gRPC-Web HTTP/2"]
C3["gRPC HTTP/2"]
end
subgraph Server["Connect server (Go/Node/Java)"]
H["Unified handler"]
end
B --> C1
M --> C2
S --> C3
C1 --> H
C2 --> H
C3 --> H
4.3. Buf breaking — tự động phát hiện breaking change
Công cụ buf có rule set breaking: chạy trong CI để so schema PR với branch chính, nó tự chặn mọi thay đổi phá hợp đồng (xoá field, đổi số field, đổi type, đổi semantic của enum). Đây là thứ REST + OpenAPI vẫn thiếu chặt chẽ; kết hợp với buf lint và buf format, contract evolution trong gRPC trở thành quy trình cơ học chứ không phụ thuộc kỷ luật developer.
4.4. Điểm mạnh và điểm yếu của gRPC năm 2026
- Mạnh: binary Protobuf giảm payload 60-80% so với JSON REST ở nội bộ hyperscale. Streaming cả 4 kiểu ở cấp framework.
- Mạnh: contract evolution tự động hoá qua buf breaking + Editions — khó lỡ tay phá compat.
- Mạnh: codegen đa ngôn ngữ chính thức (Go, Java, C++, Python, C#, Rust, Node, Kotlin, Swift, Dart) — không có protocol nào đa ngôn ngữ bằng.
- Yếu: thuần gRPC yêu cầu HTTP/2 đầu cuối — WAF, CDN, API Gateway cổ không support. Connect giải quyết được nhưng phải chọn.
- Yếu: debug qua curl không khả dụng ngoài trừ Connect JSON mode. Cần
grpcurl,buf curl, hoặc reflection server. - Yếu: HTTP caching layer gần như vô dụng — cache phải làm ở tầng application. WAF rule khó viết vì payload binary.
5. GraphQL Federation v2 và Apollo Router — BFF ở quy mô công ty
GraphQL năm 2018 hay bị lạm dụng: team nào cũng wrap REST thành GraphQL "cho sang", nhưng không giải quyết bài toán over/under-fetching cốt lõi, lại thêm gánh nặng N+1, authorization khó khoanh vùng, caching khó ở cấp CDN. Tuy nhiên, năm 2026 GraphQL đã thu hẹp về đúng lát cắt mạnh nhất của nó: Federation — một graph tổng hợp từ nhiều subgraph, thích hợp cho tổ chức có hàng chục đến hàng trăm service và nhiều BU cần chung view cho client.
5.1. Federation v2 khác gì v1
Federation v1 (2019) dùng schema stitching: gateway hợp nhất schema bằng cách directive @key, @extends. Federation v2 (2022) tiến lên composition thực thụ: Rover CLI (công cụ chính thức của Apollo) biên dịch các subgraph thành một supergraph schema duy nhất, kiểm tra trước mọi mâu thuẫn (conflict field, shareable, tag, interface object). Nếu một PR trong subgraph A phá hợp đồng của subgraph B, CI từ chối trước khi deploy.
# subgraph products
type Product @key(fields: "id") {
id: ID!
name: String!
priceMinorUnits: Int!
}
# subgraph inventory
extend type Product @key(fields: "id") {
id: ID! @external
stock: Int!
warehouse: Warehouse!
}
type Warehouse {
id: ID!
location: String!
}Supergraph schema sau khi composition sẽ có Product đầy đủ name, priceMinorUnits, stock, warehouse. Client chỉ cần biết một graph, không biết cấu trúc service nền dưới.
5.2. Apollo Router — Rust thay cho Node.js gateway
Apollo Router viết bằng Rust, thay thế Apollo Gateway cũ viết Node.js. Benchmark chính thức của Apollo cho thấy Router xử lý 3x throughput ở P99 với bộ nhớ chỉ 1/3. Router hỗ trợ query planning thông minh hơn: batching request tới subgraph, dedup field selection, và cache kết quả composition. Đối với workload 100k req/s tầm trung, Router chạy ổn định với một vài core, không phải scale ngang như Node Gateway từng phải làm.
GraphQL và caching — một điểm đau kinh điển
Vì query nằm trong POST body, CDN và reverse proxy không cache được trực tiếp. Apollo Router hỗ trợ Automatic Persisted Queries (APQ): client gửi hash của query, server lookup; CDN sau đó có thể cache theo GET URL + hash. Nếu team bạn không dùng APQ, đừng kỳ vọng CDN cache.
5.3. Authorization và rate limit — cần thiết kế riêng
GraphQL không có "endpoint" để rate-limit theo request count, vì một query có thể nặng (nested 10 tầng) hoặc nhẹ (1 field). Chuẩn mực 2026 là query cost analysis: gán cost cho mỗi field, tổng hợp theo AST của query, từ chối nếu vượt budget. Các field-level auth dùng @requires, @policy (Cedar hoặc OPA) thay vì middleware truyền thống.
5.4. Điểm mạnh và điểm yếu của GraphQL năm 2026
- Mạnh: một graph cho mọi client — BFF cho web, mobile, partner API không cần maintain nhiều endpoint.
- Mạnh: Federation v2 cho phép chia ownership theo domain team, không cần monorepo schema.
- Mạnh: client explorer (Apollo Sandbox, GraphiQL) cực mạnh cho DX.
- Yếu: N+1 mặc định; cần DataLoader và schema design kỷ luật.
- Yếu: caching CDN không tự nhiên, cần APQ + thiết kế. Auth và rate-limit phải làm ở cấp field.
- Yếu: streaming subscription qua WebSocket/SSE còn nhiều lựa chọn (graphql-ws, sse), chưa ổn định bằng gRPC streaming.
6. tRPC v11 — không schema, không codegen, chỉ có TypeScript
tRPC là con đẻ của hệ sinh thái TypeScript full-stack. Triết lý cốt lõi: nếu frontend và backend cùng viết TypeScript và cùng codebase (monorepo), thì tại sao phải định nghĩa schema trung gian? Server export type của router, client import type đó, TypeScript compiler làm cầu type-safe hai đầu. Không có codegen, không có file .proto hay .graphql, chỉ có TypeScript.
// server/router.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
const t = initTRPC.create();
export const appRouter = t.router({
product: t.router({
byId: t.procedure
.input(z.object({ id: z.string().uuid() }))
.query(async ({ input }) => {
return await db.product.findUnique({ where: { id: input.id } });
}),
list: t.procedure
.input(z.object({ cursor: z.string().optional(), take: z.number().max(100) }))
.query(async ({ input }) => {
// ...
}),
}),
});
export type AppRouter = typeof appRouter;// client/index.ts
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from '../server/router';
const trpc = createTRPCClient<AppRouter>({
links: [httpBatchLink({ url: '/api/trpc' })],
});
const product = await trpc.product.byId.query({ id: '...' });
// ^? Inferred: Product | null — không codegen, không schema trung gian6.1. tRPC v11 có gì mới
- React Server Components: server-side call không cần wrap router, có thể gọi thẳng
caller.product.byId()bên trong RSC. - Streaming response: procedure có thể trả
AsyncIterable, client nhận dần — không phải WebSocket nhưng đủ cho long-running query hoặc token streaming LLM. - Adapter đầy đủ: Hono, Elysia, Fastify, Express, Next.js, Nuxt (qua community), SvelteKit, SolidStart.
- Subscription over SSE thay WebSocket, đơn giản hoá infra edge.
6.2. Điểm mạnh và điểm yếu của tRPC năm 2026
- Mạnh: DX vượt trội cho team TS full-stack — không có bước codegen, refactor server kéo theo client tự động.
- Mạnh: Zod/Valibot schema kiêm luôn validator + type infer, giảm boilerplate.
- Mạnh: Bundle nhỏ, không runtime nặng, latency overhead gần như không có so với REST JSON.
- Yếu: chỉ type-safe trong TypeScript. Client Go/Java/Python phải tự dùng REST adapter — mất gần hết lợi ích.
- Yếu: không có contract rõ ràng cho đối tác bên ngoài. tRPC không phù hợp làm public API.
- Yếu: phụ thuộc mạnh vào monorepo và build system (tsc/SWC đủ nhanh). Microfrontend đa team, đa repo thì tRPC trở nên khó quản.
7. So sánh trực tiếp — một bảng gói gọn quyết định
| Tiêu chí | REST + OpenAPI 3.1 | gRPC / Connect | GraphQL Federation v2 | tRPC v11 |
|---|---|---|---|---|
| Schema định dạng | OpenAPI YAML/JSON + JSON Schema | Protobuf .proto (Editions) | GraphQL SDL | TypeScript types (không schema) |
| Payload | JSON (có thể CBOR/MessagePack) | Protobuf binary / JSON (Connect) | JSON | JSON (hoặc superjson) |
| Transport | HTTP/1.1, HTTP/2, HTTP/3 | HTTP/2 (Connect hỗ trợ HTTP/1.1) | HTTP/1.1, WebSocket (subscription) | HTTP/1.1, SSE, WS tuỳ adapter |
| Streaming | SSE, chunked | 4 kiểu: unary/server/client/bidi | Subscription qua graphql-ws/sse | AsyncIterable over HTTP stream |
| Codegen client | openapi-typescript, NSwag, orval, kiota | protoc + buf generate | graphql-codegen | Không cần — type inference |
| Browser native | Có (fetch) | gRPC-Web / Connect | Có (fetch) | Có (fetch) |
| Caching CDN | Rất tốt (GET + header) | Kém | Kém (cần APQ) | Trung bình (qua batch link GET) |
| Contract evolution | Thủ công + versioning URL/header | buf breaking tự động | Rover composition check | Type compiler báo lỗi |
| Polyglot | Xuất sắc | Xuất sắc | Tốt | Chỉ TypeScript |
| Phù hợp cho | Public API, B2B, BFF | Inter-service, AI serving, performance-critical | BFF nhiều domain, multi-client | Full-stack TS monorepo |
8. Ma trận quyết định — chọn theo bối cảnh
Không có protocol "tốt nhất". Có protocol phù hợp nhất với một bối cảnh cụ thể. Mình đã dùng ma trận dưới đây trong review kiến trúc cho nhiều team, phần lớn quyết định chỉ mất 30 phút nếu trả lời thành thật bốn câu:
graph TD
Start["API mới cần gì?"] --> Q1{"Public API cho
đối tác ngoài?"}
Q1 -- Có --> REST["REST + OpenAPI 3.1
Lý do: universal, cache CDN, SDK đa ngôn ngữ"]
Q1 -- Không --> Q2{"Inter-service trong
private network?"}
Q2 -- Có --> Q3{"Cần streaming
hai chiều?"}
Q3 -- Có --> GRPC["gRPC / Connect
Lý do: Protobuf binary, streaming native"]
Q3 -- Không --> Q3a{"Polyglot team?"}
Q3a -- Có --> GRPC2["gRPC / Connect"]
Q3a -- Không --> Q3b{"Full-stack TS
cùng monorepo?"}
Q3b -- Có --> TRPC["tRPC v11
Lý do: zero schema, DX vượt trội"]
Q3b -- Không --> REST2["REST + OpenAPI"]
Q2 -- Không --> Q4{"Nhiều client
cần view tổng hợp
nhiều domain?"}
Q4 -- Có --> GQL["GraphQL Federation v2
Lý do: composition schema, DX client mạnh"]
Q4 -- Không --> REST3["REST + OpenAPI"]
Kiến trúc hybrid là chuẩn mực
Thực tế production, rất ít hệ thống dùng duy nhất một protocol. Pattern phổ biến 2026: REST + OpenAPI ở edge (public API), gRPC ở tầng inter-service, GraphQL Federation làm BFF cho web/mobile app phức tạp, tRPC cho admin dashboard hoặc startup TS-only. Bài toán là chọn đúng lát cắt, không phải chọn "one true protocol".
9. Benchmark và con số thực tế
Benchmark protocol luôn gây tranh cãi vì phụ thuộc vào workload, hardware, payload shape. Mình tổng hợp con số từ ba nguồn công khai thường được trích dẫn nhất năm 2025-2026:
| Workload | REST JSON | gRPC Protobuf | GraphQL | tRPC (JSON) |
|---|---|---|---|---|
| Payload 1 entity ~1KB | ~1.1 KB | ~0.3-0.4 KB | ~1.1 KB | ~1.1 KB |
| Latency P50 (same VPC) | 1.8 ms | 0.9 ms | 2.2 ms | 1.8 ms |
| Latency P99 | 14 ms | 6 ms | 18 ms (router Rust) | 14 ms |
| Throughput (1 core server) | ~18k req/s | ~45k req/s | ~12k req/s | ~18k req/s |
| CPU per req | baseline | ~0.4x baseline | ~1.3x baseline | baseline |
Con số mang tính tham khảo cho workload CRUD đơn giản; workload thực tế (nested graph 10 tầng, aggregation analytical, binary upload) có thể ngược lại hoàn toàn. Điều rút ra ổn định qua mọi benchmark: gRPC luôn nhanh nhất cho inter-service vì payload binary + HTTP/2 multiplexing; GraphQL thường bị nặng hơn REST do overhead AST parse + resolver pipeline, nhưng Apollo Router Rust đã thu hẹp khoảng cách đáng kể; REST và tRPC gần như tương đương vì cùng JSON-over-HTTP, chỉ khác ở layer type safety.
10. Contract evolution — nơi nhiều team vấp ngã nhất
Sau một năm, API nào cũng phải tiến hoá. Khác biệt giữa protocol nằm ở chỗ: có tooling tự động chặn breaking change hay không, và nếu có thì ở tầng nào.
- REST + OpenAPI: thủ công.
oasdiffvàopenapi-diffcó thể so hai version, nhưng cần tự đặt vào CI, tự định nghĩa breaking rule. Versioning thường qua URL (/v1,/v2) hoặc header (Accept: application/vnd.api+json; version=2). Pitfall: quên update spec sau khi sửa code, dẫn đến drift. - gRPC: tự động.
buf breakingchạy trong CI với rule setWIRE_JSONhoặcWIRE, chặn mọi thay đổi phá compat. Protobuf không cần versioning URL — deprecation field qua[deprecated = true], xoá field sau chu kỳ grace. - GraphQL: rất tự động qua Apollo Rover composition check và
@tag/@deprecated. Không có versioning; evolution qua adding field mới và deprecate field cũ. Client tự chọn field cần, không có "breaking" theo nghĩa REST. - tRPC: compiler là tooling. Nếu server xoá procedure hay đổi type, client TS build fail ngay. Mạnh trong monorepo, yếu khi client và server deploy độc lập vì compile-time check không ngăn được runtime mismatch giữa các version đã deploy.
11. Authentication, authorization, observability — xương sống phải có dù chọn gì
Mọi protocol đều cần ba thứ: auth ở biên, audit log, và tracing xuyên suốt. Năm 2026 chuẩn chung là:
- OAuth 2.1 / OIDC cho auth, JWT hoặc opaque token đều được miễn chuẩn hoá qua introspection. mTLS ở tầng service-to-service cho gRPC.
- OpenTelemetry cho tracing, metric, log. Tất cả bốn protocol đều có instrumentation chính thức; W3C Trace Context header
traceparenttruyền qua metadata gRPC, header HTTP cho REST/GraphQL/tRPC. - Fine-grained authorization qua OPA/Cedar hoặc policy-as-code. GraphQL có field-level authorization native qua directive; REST/gRPC/tRPC cần middleware.
Đừng nhầm protocol với kiến trúc observability
Nhiều team chọn gRPC vì "nhanh hơn" nhưng lại để log dưới dạng string không structured, không có trace context. Protocol chỉ là wire format — observability phụ thuộc vào OpenTelemetry, structured logging, và semantic convention. Chuyển từ REST sang gRPC mà không đồng thời nâng observability thì chỉ đổi protocol chứ không tăng chất lượng vận hành.
12. Ví dụ kiến trúc thực tế — e-commerce đa protocol
Để khép lại, dưới đây là một kiến trúc e-commerce điển hình năm 2026 kết hợp cả bốn protocol, mỗi protocol đứng đúng lát cắt mạnh nhất:
graph TD
Client1["Web SPA Vue/React"] --> BFF
Client2["Mobile app iOS/Android"] --> BFF
Partner["Partner B2B"] --> PublicAPI["Public REST API
OpenAPI 3.1"]
AdminUI["Admin dashboard
Next.js + TS"] --> TRPC["tRPC v11
trong monorepo"]
BFF["GraphQL Federation Router
Apollo Router Rust"]
BFF --> Products["Products subgraph"]
BFF --> Inventory["Inventory subgraph"]
BFF --> Orders["Orders subgraph"]
BFF --> Users["Users subgraph"]
PublicAPI --> Products
PublicAPI --> Orders
Products --> PricingSvc["Pricing Service
gRPC"]
Orders --> PaymentSvc["Payment Service
gRPC + Connect"]
Orders --> FulfillmentSvc["Fulfillment Service
gRPC streaming"]
Inventory --> WarehouseSvc["Warehouse Service
gRPC streaming"]
TRPC --> Products
TRPC --> Orders
Phân tích:
- Public REST + OpenAPI: đối tác B2B tích hợp qua SDK generate từ OpenAPI, mọi ngôn ngữ. CDN cache được GET product catalog.
- GraphQL Federation: BFF cho web/mobile, tổng hợp data từ 4 domain team. Client chỉ gọi một endpoint, mobile yêu cầu đúng field cần.
- gRPC inter-service: giao tiếp giữa subgraph và service nền (Pricing, Payment, Fulfillment, Warehouse). Streaming cho update tồn kho real-time, binary Protobuf tiết kiệm băng thông.
- tRPC admin: admin dashboard và backend admin cùng monorepo, TypeScript full-stack. Ship feature admin nhanh không cần maintain thêm schema.
13. Những pitfall phải tránh khi migrate
- Nhảy từ REST sang gRPC chỉ vì hot: nếu service hiện tại chạy êm dưới 10k req/s, lợi ích binary payload không bù được chi phí re-tool observability, WAF, dev environment. gRPC thắng rõ ở scale cao hoặc cần streaming, ít hiệu quả ở CRUD đơn giản.
- Dùng GraphQL như REST: một graph một endpoint, rồi viết resolver trả toàn bộ entity. Kết quả: mất lợi thế over-fetching, còn mang thêm nặng AST. GraphQL chỉ giá trị khi schema phản ánh graph thật và client lựa field.
- tRPC cho public API: đối tác bên ngoài không có type inference. Phải tự gen REST adapter, mất hết lợi thế. tRPC là nội bộ TS — để ngoài đường biên là bài toán khó.
- OpenAPI drift: spec và code lệch nhau. Chuẩn mực 2026 là code-first sinh OpenAPI (ASP.NET Core, FastAPI, Hono) — schema phản ánh runtime thật, không còn spec viết tay lạc hậu.
- Quên backward compat: mọi protocol đều có cơ chế tương thích ngược, nhưng chỉ có gRPC Editions + buf breaking là bắt buộc; các protocol khác phụ thuộc kỷ luật team. Đặt CI check breaking từ ngày đầu, không đợi sự cố.
14. Định hướng — đặt protocol trong chiến lược API của tổ chức
Mình thường khuyên team viết một tài liệu ngắn gọn tên "API Style Guide" khoảng 3-5 trang, cố định: (1) public API chuẩn nào (REST + OpenAPI 3.1, error = ProblemDetails); (2) inter-service chuẩn nào (gRPC với Connect fallback); (3) BFF chuẩn nào (GraphQL Federation hoặc REST BFF tuỳ scale); (4) frontend admin chuẩn nào (tRPC nếu TS, REST nếu đa stack). Tài liệu này không cố tạo ràng buộc cứng, nhưng mỗi khi team mới spin up service mới, họ có default lựa chọn và không phải tranh cãi lại từ đầu.
Năm 2027 và xa hơn, xu hướng mà mình quan sát là hội tụ về schema-first: OpenAPI 3.1 + JSON Schema và Protobuf Editions đang giảm dần khoảng cách, tRPC có thể sinh OpenAPI từ router, GraphQL có thể generate từ Protobuf (qua protoc-gen-graphql). Không có lý do gì năm 2030 team phải chọn giữa "type safety monorepo" và "contract rõ ràng cho đối tác" — nhiều khả năng cả hai sẽ nằm chung trong một toolchain. Nhưng cho đến khi đó, bốn protocol trên vẫn chiếm bốn lát cắt riêng, và hiểu rõ biên giới của chúng là kỹ năng kiến trúc cơ bản cần có.
15. Tài liệu tham khảo
- OpenAPI Specification 3.1.0 — OpenAPI Initiative
- RFC 9457 — Problem Details for HTTP APIs (IETF)
- OpenAPI in ASP.NET Core — Microsoft Learn
- gRPC — Official Introduction
- Protobuf Editions Overview — protobuf.dev
- Connect RPC — Buf Technologies
- buf breaking — Breaking change detection
- Apollo Federation v2 Documentation
- Apollo Router — Rust-based GraphQL Router
- tRPC v11 Documentation
- OpenAPI 3.1 Release Announcement
- oasdiff — OpenAPI Diff & Breaking Change Detection
- OpenTelemetry Semantic Conventions
- CQRS và Event Sourcing 2026 với .NET 10 (anhtu.dev)
- .NET Aspire 9.5 + .NET 10 LTS 2026 (anhtu.dev)
OpenTelemetry 2026 cho .NET 10 - Kiến trúc Observability Microservices với OTLP, Collector, Tail Sampling, Tempo, Loki, Prometheus và Grafana
Nuxt 4 và Nitro 3 - Kiến trúc Hybrid Rendering, Islands Architecture, Server Components và Edge Deployment cho Vue Production 2026
Disclaimer: The opinions expressed in this blog are solely my own and do not reflect the views or opinions of my employer or any affiliated organizations. The content provided is for informational and educational purposes only and should not be taken as professional advice. While I strive to provide accurate and up-to-date information, I make no warranties or guarantees about the completeness, reliability, or accuracy of the content. Readers are encouraged to verify the information and seek independent advice as needed. I disclaim any liability for decisions or actions taken based on the content of this blog.