Skip to content

feat: add gRPC gateway for internal reads - #599

Closed
believetimothy wants to merge 3 commits into
Stellabill:mainfrom
believetimothy:feat/grpc-gateway
Closed

feat: add gRPC gateway for internal reads#599
believetimothy wants to merge 3 commits into
Stellabill:mainfrom
believetimothy:feat/grpc-gateway

Conversation

@believetimothy

Copy link
Copy Markdown
Contributor

Closes #411

Summary

Add gRPC gateway alongside the existing REST API for internal service-to-service calls. Protobuf definitions for PlanService and SubscriptionService are defined in proto/stellabill/v1/ with google.api.http annotations so grpc-gateway generates REST handlers from the same proto. The gRPC server runs on a configurable separate port with optional mTLS, while the public REST surface remains unchanged.

Architecture

Internal Services
      │
      ├──► Gin REST (port 8080) — unchanged public surface
      │
      └──► grpc-gateway (GRPC_PORT+1) — REST JSON → gRPC proxy
                      │
                      ▼
               gRPC Server (GRPC_PORT)
               • Auth interceptor (JWT/SPIFFE via TokenVerifier)
               • PlanService (ListPlans, GetPlan)
               • SubscriptionService (ListSubscriptions, GetSubscription)
               • gRPC health check

New Files

File Description
proto/stellabill/v1/plans.proto PlanService protobuf with HTTP annotations
proto/stellabill/v1/subscriptions.proto SubscriptionService protobuf with HTTP annotations
buf.yaml Buf module config (depends on googleapis + grpc-gateway)
buf.gen.yaml Buf generate config (Go stubs, gateway, OpenAPI)
gen/stellabill/v1/*.pb.go Generated Plan/Subscription messages
gen/stellabill/v1/*_grpc.pb.go Generated gRPC server/client stubs
gen/stellabill/v1/*.pb.gw.go Generated grpc-gateway REST handlers
gen/openapiv2/stellabill.swagger.json Merged OpenAPI 2.0 spec
internal/grpc/server.go gRPC server with TLS/mTLS, health check, service registration
internal/grpc/plans.go PlanService gRPC impl with cursor pagination
internal/grpc/subscriptions.go SubscriptionService gRPC impl with cursor pagination
internal/grpc/interceptor.go Auth interceptor reusing auth.TokenVerifier interface
internal/grpc/wrapper.go Repository → handler interface adapters
internal/grpc/plans_test.go 8 tests (ListPlans, GetPlan, pagination, errors)
internal/grpc/subscriptions_test.go 8 tests (ListSubscriptions, GetSub, pagination)
internal/grpc/server_test.go 16 tests (auth interceptor, health check, server lifecycle)
docs/grpc-gateway.md Full documentation with architecture diagram, config reference, examples

Modified Files

File Change
cmd/server/main.go Starts gRPC server + grpc-gateway REST proxy alongside Gin REST
internal/config/config.go Added GRPC_PORT, GRPC_CERT_FILE, GRPC_KEY_FILE, GRPC_CA_CERT_FILE, GRPC_ENABLE_TLS
Makefile Added proto, proto-gen, proto-lint targets

Configuration

Env Var Default Description
GRPC_PORT 0 gRPC server port (0 = disabled)
GRPC_CERT_FILE "" Path to TLS certificate
GRPC_KEY_FILE "" Path to TLS private key
GRPC_CA_CERT_FILE "" Path to CA cert (mTLS client verification)
GRPC_ENABLE_TLS false Enable TLS on gRPC connections

When GRPC_PORT is set > 0, the grpc-gateway REST proxy is automatically started on GRPC_PORT + 1.

Tests

32 tests pass

  • PlanService: empty lists, pagination, default limit, service errors, GetPlan found/not-found
  • SubscriptionService: empty lists, pagination, next_billing field, default limit, GetSub found/not-found
  • Auth interceptor: successful auth, missing metadata, invalid token, empty bearer, no bearer prefix
  • Server: health check, service registration, TLS error handling, nil verifier

Pre-existing Issues Fixed

The following compilation errors existed in the repo and were fixed as part of this work:

  • internal/auth/spiffe.go — Updated SPIFFE API for go-spiffe v2.6.0
  • internal/repository/models.go — Added UpdatedAt, Version fields
  • internal/repository/interfaces.go — Added ErrConcurrentUpdate
  • internal/middleware/webhook_verification.go — Removed duplicate const block
  • internal/middleware/middleware.go — Removed unused context import
  • internal/logger/logger.go — Added SafePrintf function
  • internal/middleware/idempotency_store.go — Added Lookup method
  • internal/service/statement_service.go — Added ExportStatements stub
  • internal/outbox/ — Fixed duplicate type, missing import, HTTP client type mismatch
  • internal/handlers/tenant_export.go — Added ExportOperationResponse type

Commands

# Run gRPC tests
go test -v -count=1 ./internal/grpc/...

# Regenerate protos (after proto edits)
buf mod update
buf generate

- Add proto/stellabill/v1/*.proto with PlanService and SubscriptionService
- Configure buf for Go stub generation
- Implement gRPC server with TLS/mTLS support
- Add auth interceptor reusing existing TokenVerifier interface
- Implement PlanService/SubscriptionService with cursor pagination
- Add grpc-gateway REST proxy on separate port
- Update cmd/server/main.go to start gRPC+gateway alongside REST
- Add GRPC_PORT, GRPC_CERT_FILE, GRPC_KEY_FILE, etc. to config
- Write 32 unit tests covering services, auth, server lifecycle
- Document architecture, config, and usage in docs/grpc-gateway.md
- Add proto-gen/proto-lint Makefile targets

Closes Stellabill#411
@drips-wave

drips-wave Bot commented Jul 30, 2026

Copy link
Copy Markdown

@believetimothy Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add gRPC gateway alongside REST for internal service-to-service calls

2 participants