99. Case Study: Admin Dashboard Built with grpc-gateway
99. Case Study: Admin Dashboard Built with grpc-gateway
The admin dashboard is the beating heart of managing large-scale applications. Behind its buttons and statistics tables lies a real architectural challenge: how backend services communicate with one another. One modern way to build a robust yet developer-friendly API is grpc-gateway. In this case study, we will dig into how to build an admin dashboard powered by grpc-gateway, complete with design considerations, code examples, flow simulations, and best practices.
Introduction: When REST Is No Longer Enough
Many applications start out with a REST API. But as data volume grows, real-time needs emerge, and the demand for multi-platform integration increases, this protocol starts to feel inefficient. gRPC, built on HTTP/2 and Protocol Buffers, offers performance and type safety. However, pure gRPC is not yet universal: not every frontend is ready to speak gRPC natively. This is exactly the gap that grpc-gateway fills: an automatic bridge from gRPC to a RESTful API.
Case Study: A User Performance Admin Dashboard
Suppose we have a SaaS application with an admin team that manages users, monitors usage, and intervenes whenever an anomaly occurs. We want an admin dashboard that:
- Displays user statistics in real time.
- Performs user CRUD with fast responses.
- Is accessible from a web frontend (through RESTful endpoints).
- Has an efficient backend, a well-designed schema, and is easy to scale.
Architecture Choices
| Layer | Chosen Stack | Rationale |
|---|---|---|
| Frontend | React + fetch | Familiar, REST endpoint ready |
| API Gateway | grpc-gateway (Go) | Translates HTTP(JSON) <-> gRPC |
| Backend | gRPC Microservices (GoLang) | High-perf, strong typing |
| Storage | PostgreSQL | Consistent, great for analytics |
Protobuf Definition: Define the API Once for Everyone
gRPC starts from a single source of truth: the .proto file. For example, user.proto:
1syntax = "proto3";
2
3package admin;
4
5service UserService {
6 rpc GetUserStats (StatsRequest) returns (StatsResponse) {
7 option (google.api.http) = {
8 get: "/admin/users/stats"
9 };
10 }
11
12 rpc ListUsers (ListUsersRequest) returns (ListUsersResponse) {
13 option (google.api.http) = {
14 get: "/admin/users"
15 };
16 }
17
18 rpc CreateUser (CreateUserRequest) returns (User) {
19 option (google.api.http) = {
20 post: "/admin/users"
21 body: "*"
22 };
23 }
24
25 rpc DeleteUser (DeleteUserRequest) returns (Empty) {
26 option (google.api.http) = {
27 delete: "/admin/users/{id}"
28 };
29 }
30}
31
32message StatsRequest {}
33message StatsResponse {
34 int32 active_user_count = 1;
35 int32 total_user_count = 2;
36}
37
38message User {
39 string id = 1;
40 string name = 2;
41 string email = 3;
42}
43
44message ListUsersRequest {
45 int32 page = 1;
46 int32 per_page = 2;
47}
48message ListUsersResponse {
49 repeated User users = 1;
50}
51
52message CreateUserRequest {
53 string name = 1;
54 string email = 2;
55}
56
57message DeleteUserRequest {
58 string id = 1;
59}
60message Empty {}Implementing the gRPC Backend
For example, in GoLang (a popular implementation for gRPC):
1// user_service.go
2func (s *Server) GetUserStats(ctx context.Context, req *pb.StatsRequest) (*pb.StatsResponse, error) {
3 stats, err := s.repo.FetchStats() // Fetch from Postgres, for example
4 if err != nil {
5 return nil, status.Errorf(codes.Internal, "FetchStats: %v", err)
6 }
7 return &pb.StatsResponse{
8 ActiveUserCount: stats.Active,
9 TotalUserCount: stats.Total,
10 }, nil
11}Setting up grpc-gateway
grpc-gateway reads the google.api.http annotations in the proto and generates an HTTP -> gRPC proxy converter.
For example, in a Go Mod project:
Generate code from
.proto:1protoc -I. --go_out=. --go-grpc_out=. --grpc-gateway_out=. user.protoImplement the gateway handler:
1mux := runtime.NewServeMux() 2err := admin.RegisterUserServiceHandlerServer(ctx, mux, userServer) 3if err != nil { 4 log.Fatalf("Failed to register: %v", err) 5} 6http.ListenAndServe(":8080", mux)
/admin/users/stats, /admin/users, and so on as REST endpoints, while forwarding the requests to the gRPC handlers.Simulating the Request Flow
For example, a React frontend fetching user statistics:
1fetch("/admin/users/stats")
2 .then(res => res.json())
3 .then(res => console.log(res));On the backend:
- HTTP GET
/admin/users/stats - grpc-gateway converts it into the
GetUserStatsgRPC call - The GoLang handler runs the business logic
- The result is returned to the frontend in JSON format
Flow Diagram (mermaid)
sequenceDiagram participant Frontend participant grpc-gateway participant UserService (gRPC) participant Database Frontend->>grpc-gateway: GET /admin/users/stats grpc-gateway->>UserService (gRPC): GetUserStats() UserService (gRPC)->>Database: SQL SELECT COUNT() Database-->>UserService (gRPC): Stats UserService (gRPC)-->>grpc-gateway: StatsResponse grpc-gateway-->>Frontend: JSON Stats
Benchmark: Efficiency
A brief analysis of a performance simulation:
| Connection Method | RPS (req/sec) | Median Latency (ms) |
|---|---|---|
| Legacy REST API | 950 | 120 |
| Native gRPC | 1,500 | 40 |
| grpc-gateway API | 1,400 | 45 |
With grpc-gateway, we get performance almost on par with native gRPC, while keeping the flexibility of REST.
Testing and Observability
You can still write unit/integration tests against the gRPC handlers, and only need e2e tests at the grpc-gateway layer. grpc-gateway is mature and easily supports OpenAPI docs as well as logging middleware, ensuring observability.
1mux := runtime.NewServeMux(
2 runtime.WithForwardResponseOption(myLoggingResponseModifier),
3)Comparison: REST vs grpc-gateway
| Feature | REST-Only | grpc-gateway |
|---|---|---|
| Strong typing | Weak | Very strong (proto) |
| Auto SDK generation | Usually manual | Yes (from proto) |
| OpenAPI documentation | Swagger | Automatic from proto |
| Performance | Standard | Close to native gRPC |
| Migration to native gRPC | Difficult | Very easy |
Notes and Best Practices
- Always start from the proto file: Treat the proto as the single source of truth for the API.
- Use the google.api.http annotations consistently so that REST endpoints are always available.
- Separate gateway handlers from backend logic—keep the REST handlers simple and put the heavy logic in the gRPC handlers.
- Version your proto and endpoints whenever there are major schema changes.
- Tracing and monitoring across layers is essential for debugging in production.
Conclusion
With grpc-gateway, the backend team can write modern, efficient, and future-proof APIs while still serving the common RESTful APIs needed by frontends, mobile apps, integrators, and other legacy clients. This admin dashboard case study showcases the power of the pattern: define once, use everywhere. For your next project, strongly consider starting from gRPC + grpc-gateway.
Want to try the sources?
gRPC-Gateway Documentation
Example code at github.com/your-repo/admin-dashboard-grpc-gateway
Thanks for reading!
Leave a comment if you would like an even deeper case study.