Phong cách API trong .NET: REST vs gRPC vs GraphQL
Cách chọn giữa REST, gRPC, GraphQL trong .NET, khi nào BFF giúp, và mỗi style thực sự tốn gì về latency và thời gian dev.
Mục lục
Lựa chọn API style được quyết định trong cuộc họp design đầu tiên và sống trong từng dòng code client về sau. Chọn sai, team sẽ xoay xở quanh nó nhiều năm. Chương này chia lựa chọn thành ba loại quan trọng cho .NET - REST, gRPC, GraphQL - cộng pattern BFF giải quyết nỗi đau tổng hợp riêng.
Khi nào API style thực sự quan trọng?
Ba tín hiệu.
Nhiều client, hình dạng khác nhau. Web muốn display name của user và mobile muốn cùng đó cộng ảnh profile và partner muốn view chỉ ID, REST endpoint nhân lên. GraphQL gộp lại.
Budget latency nội bộ chặt. Service A gọi Service B 50 lần để render một request. Mỗi lần thêm parse JSON và overhead HTTP. Protobuf nhị phân của gRPC cắt chi phí mỗi lần ~3-5x và HTTP/2 multiplex chúng trên một connection.
Trải nghiệm dev ngoài quan trọng. API public cho partner được con người đọc bằng curl. JSON thắng; Protobuf khó đọc nếu không có tooling.
Nếu không cái nào trội, REST + JSON là mặc định đúng. 80% service .NET còn lại không bao giờ cần gì khác.
Ngân sách số nào cho lựa chọn này?
Style Kích thước payload Encode/decode Thân thiện browser
REST+JSON 1x baseline ~50 µs có
gRPC ~0.3-0.6x ~10-20 µs không (cần grpc-web)
GraphQL thay đổi (tuỳ) ~50-100 µs có
Cho latency mỗi call, mạng lấn át mọi thứ với hop bất kỳ > 1 ms. Đổi REST sang gRPC tiết kiệm ~30 µs CPU; nếu service xuyên internet ở RTT 50 ms, nó vô hình. Lợi ích gRPC hiện ra trong data centre ở RTT <1 ms, nơi tiết kiệm CPU có ý nghĩa.
Kiến trúc tối thiểu trông thế nào?
flowchart LR
Web[Web client] -->|REST+JSON| Edge[ASP.NET Core API]
Mobile[Mobile client] -->|REST+JSON| Edge
Edge -->|gRPC| SvcA[Service inventory]
Edge -->|gRPC| SvcB[Service pricing]
Edge -->|gRPC| SvcC[Service user]
Edge --> DB[(Postgres)]
Client ngoài nói REST+JSON; service nội nói gRPC. Service edge dịch
- một REST endpoint hậu thuẫn bởi ba gRPC nội bộ. Đây là hình dạng phổ biến nhất trong stack microservice .NET trưởng thành và cho bạn cả hai ergonomic ở chỗ quan trọng.
Cấu hình .NET 10 trông ra sao?
REST có sẵn trong ASP.NET Core - không setup. gRPC cần file
.proto cộng package:
// inventory.proto - contract chia sẻ
service Inventory {
rpc GetStock (StockRequest) returns (StockReply);
}
message StockRequest { string sku = 1; }
message StockReply { int32 quantity = 1; bool available = 2; }
// Phía server
builder.Services.AddGrpc();
app.MapGrpcService<InventoryGrpcService>();
public class InventoryGrpcService(IStockRepo repo) : Inventory.InventoryBase
{
public override async Task<StockReply> GetStock(StockRequest req, ServerCallContext ctx)
{
var qty = await repo.GetQuantityAsync(req.Sku, ctx.CancellationToken);
return new StockReply { Quantity = qty, Available = qty > 0 };
}
}
// Phía client - client sinh tự động, dùng như service bình thường
builder.Services.AddGrpcClient<Inventory.InventoryClient>(o =>
{
o.Address = new Uri("https://inventory:5001");
});
public class CheckoutService(Inventory.InventoryClient inv)
{
public async Task<bool> CanFulfill(string sku)
{
var reply = await inv.GetStockAsync(new StockRequest { Sku = sku });
return reply.Available;
}
}
GraphQL với Hot Chocolate trông tương tự - schema-first hoặc code-first, map sang type domain, với DataLoader sẵn để giải bài N+1. Ví dụ đầy đủ vừa khít trong bất kỳ Hot Chocolate quickstart và quá dài để inline ở đây.
Tránh sai lầm cổ điển về API style ra sao?
Bốn sai lầm tôi liên tục gặp khi review:
- REST verb nói dối -
POST /searchổn;POST /getUserthì không. Hoặc dùng đúng HTTP verb hoặc dùng gRPC. Trộn cả hai mất HTTP cache và làm client bối rối. - gRPC qua internet - payload Protobuf nhỏ nhưng overhead connection HTTP/2 có thật, và nhiều proxy doanh nghiệp phá gRPC. Trong data centre, ổn. Qua internet đến partner, REST.
- GraphQL không DataLoader - bài N+1 query là mặc định trong GraphQL; một query cho post cộng một query cho mỗi post lấy author. DataLoader batch chúng. Quên là giết database.
- Một BFF cho nhiều client - mục đích BFF là tuỳ biến từng client. Chia sẻ một BFF cho iOS, Android, Web biến nó thành tầng giữa cồng kềnh có cái dở của mọi cái.
Mỗi style tạo failure mode nào?
- REST - schema drift giữa client và server (không contract); N+1 call khi resource hình graph. Sửa: OpenAPI + client sinh tự động; thiết kế endpoint cho màn hình, không cho entity.
- gRPC - payload mờ làm debug production khó hơn; vấn đề tương thích proxy; khó test bằng curl. Sửa: log message serialised ở edge, lộ REST gateway cho công cụ tạm.
- GraphQL - tấn công query complexity (một
nested(depth:50)làm quá tải server); biến thiên phá cache (mỗi query string khác). Sửa: giới hạn complexity của Hot Chocolate + persisted query.
Chương 13 instrument cả ba đồng đều qua hỗ trợ HTTP/gRPC của OpenTelemetry.
Khi nào nên bỏ qua tranh luận API style?
Khi traffic thấp và team nhỏ. Một REST API trên ASP.NET Core lo được 10K QPS thoải mái. Lợi gRPC quan trọng ở quy mô service mesh; lợi GraphQL quan trọng ở quy mô đa nền tảng. Startup với một API và một mobile app không nhận được gì từ cả hai ngoài phức tạp. Ở lại REST + JSON cho đến khi ước lượng QPS hoặc nỗi đau đa client ép thay đổi thật sự.
Đi tiếp đâu từ đây?
Chương kế tiếp: Elasticsearch trong app .NET - khi query LIKE trên Postgres không còn đáp ứng nổi và bạn cần search engine thật. Sau đó, phong cách auth khép lại nhóm building blocks.