Day 124 — Reflection & grpcurl¶
Month 5 · Week 2 · ⬅ Day 123 · Day 125 ➡ · Journal index
🎯 Learning Objective¶
Enable server reflection and use grpcurl to discover and call gRPC methods without a hand-written client or the .proto files.
📚 Topics¶
reflection.Register(server)and the reflection servicegrpcurl list/describe/ calling methods with JSONhealthchecking; when to disable reflection
📖 Reading / Sources¶
- gRPC Server Reflection protocol
- gRPC-Go
reflectionpackage -
grpcurlREADME - gRPC Health Checking Protocol
📝 Notes¶
- Server reflection lets a client ask the server "what services and methods do you expose, and what do their messages look like?" at runtime. Enable it with one line:
reflection.Register(grpcServer)→ [[reflection]]. - With reflection on,
grpcurliscurlfor gRPC: no.protoneeded because it pulls the schema from the server. It's the fastest way to smoke-test a service → [[grpcurl]]. - Core commands:
grpcurl -plaintext localhost:50051 list(services),... list pkg.Service(methods),... describe pkg.Message(fields), and call:grpcurl -plaintext -d '{"id":"42"}' localhost:50051 pkg.Users/GetUser→ [[tooling]]. -plaintextskips TLS for local dev; against a TLS server use-cacert/-cert/-key. Pass metadata with-H 'authorization: Bearer tok'to exercise the auth interceptor from Day 121 → [[transport-security]].- The health service (
grpc.health.v1.Health) is a standard probe:grpc_health_probeorgrpcurl ... grpc.health.v1.Health/CheckreturnsSERVING. Load balancers and k8s readiness probes use it → [[health-check]]. - Security note: reflection exposes your full API surface. Many teams enable it in dev/staging and disable it in production, or gate it behind auth, to avoid handing attackers a map.
- Without reflection you can still call a server by pointing grpcurl at the
.proto/descriptor:grpcurl -import-path . -proto user.proto ....
💻 Code Examples¶
import (
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"google.golang.org/grpc/health"
healthpb "google.golang.org/grpc/health/grpc_health_v1"
)
srv := grpc.NewServer()
userpb.RegisterUsersServer(srv, &usersImpl{})
// Register the health service and reflection (dev/staging).
hs := health.NewServer()
hs.SetServingStatus("", healthpb.HealthCheckResponse_SERVING)
healthpb.RegisterHealthServer(srv, hs)
reflection.Register(srv) // <- grpcurl can now discover everything
# Discover and call, no .proto files needed:
grpcurl -plaintext localhost:50051 list
grpcurl -plaintext localhost:50051 describe user.Users
grpcurl -plaintext -H 'authorization: Bearer tok-abc' \
-d '{"id":"42"}' localhost:50051 user.Users/GetUser
🏋️ Exercises / Practice¶
| Exercise | Status | Link |
|---|---|---|
(tooling) grpcurl list → describe → call a method |
✅ | day note snippet |
(tooling) Probe grpc.health.v1.Health/Check |
✅ | day note snippet |
🐛 Mistakes Made¶
- Ran
grpcurlagainst a TLS server with-plaintextand got a cryptic connection error — the flag must match the server's transport. Dropped-plaintextand added-cacert. - Left reflection registered in a "prod-like" build before realizing it advertises the whole API; noted to gate it by environment.
❓ Open Questions¶
- Can reflection be scoped to expose only a subset of services, or is it all-or-nothing?
🧠 Active Recall (answer without looking)¶
- Q: Why can
grpcurlcall a service without its.protofiles?
A
Because server reflection (registered via `reflection.Register`) lets the server return its own service/message descriptors at runtime; grpcurl fetches the schema from the server.- Q: Why might you disable reflection in production?
A
It exposes the full API surface (every service, method, and message) to anyone who can reach the port, which aids attackers. Teams often keep it on in dev/staging only or gate it behind auth.🪶 Feynman Reflection¶
Reflection is the server publishing its own table of contents. Normally a client needs the .proto to know what to call; with reflection on, it just asks the server "what have you got?" and the server hands back the menu. grpcurl is the diner that reads that menu and orders — no cookbook required.
🕳️ Knowledge Gaps¶
- Whether descriptor caching in grpcurl can go stale after a redeploy.
✅ Summary¶
I can enable reflection and the health service, and drive a running gRPC server end-to-end with grpcurl (list, describe, call, with auth metadata), plus reason about when reflection is unsafe.
⏭️ Next Steps / Prep for Tomorrow¶
- Day 125: writing tests for gRPC services with
bufconn.
| Time spent | Difficulty | Confidence |
|---|---|---|
| 90 min | 🟦⬜⬜⬜⬜ | 🟦🟦🟦🟦⬜ |
Suggested commit: docs(journal): server reflection & grpcurl workflow (day 124)