Local gRPC Gateway
This document describes how to set up a local HTTP/JSON to gRPC transcoding proxy using gRPC-Gateway, as an alternative to ESPv2.
Overview
gRPC-Gateway is a plugin of protoc that generates a reverse-proxy server which translates a RESTful HTTP API into gRPC. This approach:
- Runs natively on your development machine (no Docker required)
- Works offline with no cloud dependencies
- Generates OpenAPI specs automatically for your Java ADK
- Provides full control over transcoding configuration
Architecture
HTTP Client -> gRPC-Gateway Proxy (port 8082) -> gRPC Server (port 8080)
Prerequisites
- Go 1.22+ (automatically installed by setup script)
- Protocol Buffers compiler (
protoc) - Your gRPC server running on port 8080
Quick Start
- Start your gRPC server:
./cli/start-local-server.sh
Test the gRPC server is running:
Prerequisite: Install grpcurl if not already installed:
# Install grpcurl if not already installed in Dev Container
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
export PATH=$PATH:~/go/bin
Prerequisite: Install Go protoc plugins. The following commands will install the necessary tools for generating the gateway code:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest
# When running from the host machine (not in a Docker container)
GRPC_SERVER_HOST=localhost:8080
# When running from within the Dev Container
# This isn't working.
# GRPC_SERVER_HOST=host.docker.internal:8080
# When running from within the Dev Container
# Use the actual host machine IP address
GRPC_SERVER_HOST=192.168.1.96
grpcurl -import-path src/main/proto \
-import-path env/dependencies/googleapis \
-proto src/main/proto/api.proto \
-d '{"account_id": "test@example.com", "filter": ""}' \
-plaintext \
${GRPC_SERVER_HOST}:8080 \
org.codetricks.construction.code.assistant.service.ArchitecturalPlanService/ListArchitecturalPlanIds
- Start the gRPC-Gateway proxy:
Running on a MacOS localhost machine (not in a Docker container):
# Install go if not already installed
brew install go
./cli/start-local-grpc-gateway.sh
- Test the HTTP API:
# Set variables for testing (adjust these for your environment)
GRPC_SERVER_HOST=192.168.1.96
GATEWAY_PORT=8082 # 8081 is reserved for gRPC ESPv2 Proxy
PLAN_ID="A.0155.01-2025-06-12"
PAGE_NUMBER=1
ICC_BOOK_ID=2217
# List all architectural plans
curl -X GET http://${GRPC_SERVER_HOST}:${GATEWAY_PORT}/v1/architectural-plans
# Get a specific architectural plan by ID
curl -X GET http://${GRPC_SERVER_HOST}:${GATEWAY_PORT}/v1/architectural-plans/${PLAN_ID}
# Get applicable code sections for a specific plan page
curl -X POST -H "Content-Type: application/json" \
-d '{"iccBookId": "'${ICC_BOOK_ID}'"}' \
http://${GRPC_SERVER_HOST}:${GATEWAY_PORT}/v1/architectural-plans/${PLAN_ID}/pages/${PAGE_NUMBER}/applicable-code-sections
# Search ICC codes semantically
curl -X POST -H "Content-Type: application/json" \
-d '{"query": "fire resistance", "maxResults": 5}' \
http://${GRPC_SERVER_HOST}:${GATEWAY_PORT}/v1/icc-books/${ICC_BOOK_ID}/search
# Get ICC book table of contents
curl -X POST -H "Content-Type: application/json" \
-d '{}' \
http://${GRPC_SERVER_HOST}:${GATEWAY_PORT}/v1/icc-books/${ICC_BOOK_ID}/table-of-contents
# Get architectural plan page PDF (requires plan ID and page number)
curl -X POST -H "Content-Type: application/json" \
-d '{}' \
http://${GRPC_SERVER_HOST}:${GATEWAY_PORT}/v1/architectural-plans/${PLAN_ID}/pages/${PAGE_NUMBER}/pdf
# Check authorization status
curl -X POST -H "Content-Type: application/json" \
-d '{"resource_accessed": "architectural_plans", "client_email": "user@example.com"}' \
http://${GRPC_SERVER_HOST}:${GATEWAY_PORT}/v1/authorization
Note: The authorization endpoint requires the AccessControlListService to be enabled in the gateway configuration. Currently, this service is commented out in main.go.
- Access the OpenAPI spec:
curl http://${GRPC_SERVER_HOST}:${GATEWAY_PORT}/openapi.json
Generated Files
The setup generates several files in env/local/grpc-gateway/src/go/generated/:
*.pb.go- Protocol buffer Go bindings*_grpc.pb.go- gRPC service definitions*.gw.go- gRPC-Gateway reverse proxy code*.swagger.json- OpenAPI v2 specification
The source-controlled files are in env/local/grpc-gateway/src/go/:
main.go- The proxy server implementationgo.mod- Go module definition
Configuration
The proxy server runs on port 8082 by default and connects to your gRPC server on localhost:8080.
Environment Variables
GRPC_GATEWAY_PORT- HTTP proxy port (default: 8082)GRPC_SERVER_PORT- gRPC backend port (default: 8080)GRPC_SERVER_HOST- gRPC backend host (default: localhost)
API Endpoints
Based on your protobuf annotations, the following endpoints are available:
ArchitecturalPlanService
GET /v1/architectural-plans- List architectural plansGET /v1/architectural-plans/{architectural_plan_id}- Get specific planPOST /v1/architectural-plans/{architectural_plan_id}/pages/{page_number}/pdf- Get plan page PDF
ArchitecturalPlanReviewService
POST /v1/architectural-plans/{architectural_plan_id}/pages/{page_number}/applicable-code-sections- Get applicable code sectionsPOST /v1/icc-books/{icc_book_id}/table-of-contents- Get ICC book table of contents
ComplianceCodeSearchService
POST /v1/icc-books/{icc_book_id}/search- Search ICC codes
AccessControlListService
POST /v1/auth/authorization-status- Check authorization status
OpenAPI Integration
The generated *.swagger.json file can be used with:
- Java ADK - For agentic tool calls
- Swagger UI - For interactive API documentation
- Postman - For API testing
- Code generators - For client library generation
OpenAPI Format Support
The gRPC-Gateway proxy provides OpenAPI specifications in multiple formats:
- JSON Format:
http://localhost:8082/openapi.json- Native JSON format - YAML Format:
http://localhost:8082/openapi.yaml- YAML content-type header
Current YAML Implementation Trade-offs
What we have:
- ✅ True YAML syntax conversion using Go YAML library
- ✅ No external dependencies (pure Go implementation)
- ✅ Works with all tools including Java ADK
- ✅ Human-readable YAML format
- ✅ Proper error handling and logging
Example of current /openapi.yaml output:
swagger: "2.0"
info:
title: "api.proto"
version: "version not set"
tags:
- name: "ArchitecturalPlanService"
paths:
/v1/architectural-plans:
get:
summary: "Lists the IDs of all available architectural plans..."
Note: This is now true YAML content served with Content-Type: text/yaml
Implementation Details
Option 2: Use Go YAML library ✅ IMPLEMENTED
// Add gopkg.in/yaml.v3 to go.mod
// Implement proper JSON to YAML conversion in Go
Status: ✅ Implemented with gopkg.in/yaml.v3 library. The /openapi.yaml endpoint now provides true YAML syntax.
Alternative options for future reference:
Option 1: Install yq for proper conversion
# Install yq for JSON to YAML conversion
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq
chmod +x /usr/local/bin/yq
# Update the Go code to use yq for conversion
Option 3: Generate YAML directly from protoc
# Use protoc-gen-openapiv2 with YAML output option
protoc --openapiv2_out=format=yaml:generated/ ...
Current implementation: Option 2 (Go YAML library) provides native YAML conversion without external dependencies.
Troubleshooting
Port Conflicts
If port 8082 is in use, set a different port:
export GRPC_GATEWAY_PORT=8083
./cli/start-local-grpc-gateway.sh
gRPC Connection Issues
Ensure your gRPC server is running and accessible:
# Check if gRPC server is running
netstat -tlnp | grep 8080
# Test gRPC server directly (if grpcurl is available)
grpcurl -plaintext localhost:8080 list
Regenerating Code
If you modify your .proto files, regenerate the gateway code:
./cli/start-local-grpc-gateway.sh --regenerate
Comparison with ESPv2
| Feature | gRPC-Gateway | ESPv2 |
|---|---|---|
| Offline Operation | ✅ Full offline | ⚠️ Requires cloud config |
| Native Performance | ✅ Native ARM64 | ⚠️ Docker emulation |
| OpenAPI Generation | ✅ Automatic | ⚠️ Manual configuration |
| Local Development | ✅ Designed for local | ⚠️ Designed for cloud |
| Configuration | ✅ Simple protobuf annotations | ⚠️ Complex YAML + descriptors |
| Dependencies | ✅ Go toolchain only | ⚠️ Docker + Google Cloud tools |
Next Steps
- Integrate with Java ADK - Use the generated
*.swagger.jsonfor tool definitions - Add authentication - Implement JWT or API key validation
- Add monitoring - Integrate with your logging/metrics system
- Customize responses - Add custom error handling and response formatting
Files Structure
├── cli/
│ └── start-local-grpc-gateway.sh # Startup script
├── env/
│ └── local/
│ └── grpc-gateway/
│ └── src/go/ # Go module directory
│ ├── main.go # Proxy server implementation
│ ├── go.mod # Go module definition
│ ├── go.sum # Go module checksums
│ └── generated/ # Generated Go code and OpenAPI spec
│ ├── *.pb.go # Protocol buffer bindings
│ ├── *.gw.go # gRPC-Gateway handlers
│ └── *.swagger.json # OpenAPI specification
├── src/main/proto/ # Your protobuf definitions
└── README-grpc-gateway.md # This file