Skip to content

REST Gateway

The gRPC Gateway provides REST/HTTP access to angzarr services with auto-generated OpenAPI documentation.

flowchart LR
    RC["REST Client<br/>(HTTP)"] --> GW["gRPC Gateway<br/>(port 8080)"]
    GW --> AC["Aggregate Coord<br/>(port 1310)"]
    GW -.-> TB["types.bin<br/>(proto desc)"]

The gateway patches its OpenAPI spec with your domain types (events, commands) by reading a proto descriptor file at startup.

Use buf build to generate a binary FileDescriptorSet from your proto files:

Terminal window
# For angzarr examples (poker domain)
just examples descriptor # Generates examples/types.bin
# For your own protos
cd proto && buf build -o types.bin --path your-domain/

The --path flag filters to specific directories. For multiple domains:

Terminal window
buf build -o types.bin --path player/ --path table/ --path hand/

The gateway extracts all message types and classifies them:

  • Events: Types ending in past tense (Created, Updated, Completed, etc.)
  • Commands: Types starting with imperative verbs (Create, Register, Execute, etc.)

The OpenAPI spec is patched with:

  • Individual type definitions under discovered.*
  • Composite discovered.AnyEvent and discovered.AnyCommand with oneOf schemas
Terminal window
# Generate descriptor
just examples descriptor
# Create ConfigMap
kubectl create configmap gateway-descriptor -n angzarr \
--from-file=types.bin=examples/types.bin
# Update ConfigMap (if it exists)
kubectl create configmap gateway-descriptor -n angzarr \
--from-file=types.bin=examples/types.bin \
--dry-run=client -o yaml | kubectl apply -f -

Deployment configuration:

apiVersion: apps/v1
kind: Deployment
metadata:
name: angzarr-grpc-gateway
spec:
template:
spec:
containers:
- name: gateway
image: ghcr.io/angzarr-io/angzarr-grpc-gateway:latest
env:
- name: GRPC_TARGET
value: "your-aggregate-coordinator:1310"
- name: DESCRIPTOR_PATH
value: "/config/types.bin"
volumeMounts:
- name: descriptor
mountPath: /config
readOnly: true
volumes:
- name: descriptor
configMap:
name: gateway-descriptor

For simpler deployments, include the descriptor in the image:

FROM ghcr.io/angzarr-io/angzarr-grpc-gateway:latest
COPY types.bin /app/types.bin
ENV DESCRIPTOR_PATH=/app/types.bin
Terminal window
# Generate descriptor
just examples descriptor
# Run gateway with descriptor
DESCRIPTOR_PATH=./examples/types.bin \
go run ./gateway --grpc-target=localhost:1310
EndpointDescription
GET /healthHealth check
GET /openapi.jsonOpenAPI spec (patched with discovered types)
GET /discovery/infoType discovery status
GET /discovery/typesList of discovered types
GET /discovery/collisionsType name collision report
{
"type_count": 75,
"event_count": 17,
"command_count": 7,
"has_collisions": false
}

When multiple domains define types with the same short name, the gateway detects collisions:

{
"HasCollisions": true,
"Collisions": {
"Created": [
"player.PlayerCreated",
"table.TableCreated"
]
}
}

Collisions don’t prevent the gateway from working, but the OpenAPI spec will use fully-qualified names to avoid ambiguity.

Environment VariableFlagDefaultDescription
GRPC_TARGET--grpc-targetlocalhost:1310Backend gRPC coordinator
DESCRIPTOR_PATH--descriptor-file(none)Path to proto descriptor (shared with angzarr core)
---http-port8080HTTP listen port

The angzarr-domain Helm chart includes gateway configuration:

values.yaml
grpcGateway:
enabled: true
image: ghcr.io/angzarr-io/angzarr-grpc-gateway:latest
port: 8080
nodePort: 31808 # Optional: for dev access
descriptorConfigMap: gateway-descriptor