Skip to main content

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

  1. 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
  1. 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
  1. 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.

  1. 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 implementation
  • go.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 plans
  • GET /v1/architectural-plans/{architectural_plan_id} - Get specific plan
  • POST /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 sections
  • POST /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 libraryIMPLEMENTED

// 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

FeaturegRPC-GatewayESPv2
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

  1. Integrate with Java ADK - Use the generated *.swagger.json for tool definitions
  2. Add authentication - Implement JWT or API key validation
  3. Add monitoring - Integrate with your logging/metrics system
  4. 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