REST & gRPC Subgraphs
HyperRoute natively supports REST and gRPC services as federated subgraphs — no connector plugins, no code generation, no sidecar proxies. Configure the mapping in YAML or use schema directives.
Protocol Support Matrix
| Feature | GraphQL | REST | gRPC |
|---|---|---|---|
| Query | ✅ | ✅ | ✅ |
| Mutation | ✅ | ✅ | ✅ |
| Subscription | ✅ (SSE/WS) | — | — |
| Entity Resolution | ✅ | ✅ | ✅ |
| Connection Pooling | ✅ HTTP/2 | ✅ HTTP/2 | ✅ HTTP/2 |
| Retry | ✅ | ✅ | ✅ |
| Circuit Breaker | ✅ | ✅ | ✅ |
REST Subgraphs
Config-Based Mapping
Define REST-to-GraphQL mappings in your router configuration:
upstreams:
users:
url: http://users-api:3000
type: rest
mappings:
- field: Query.user
method: GET
path: /api/users/{args.id}
response_mapping: "data.user"
- field: Query.users
method: GET
path: /api/users
query_params:
limit: "{args.limit}"
offset: "{args.offset}"
- field: Mutation.createUser
method: POST
path: /api/users
body: "{args.input}"
- field: User._entities
method: GET
path: /api/users/{keys.id}
Directive-Based Mapping
Alternatively, define mappings directly in your GraphQL schema using directives:
type Query {
user(id: ID!): User
@rest(method: GET, path: "/api/users/{args.id}")
users(limit: Int, offset: Int): [User!]!
@rest(method: GET, path: "/api/users", query: { limit: "{args.limit}", offset: "{args.offset}" })
}
type Mutation {
createUser(input: CreateUserInput!): User
@rest(method: POST, path: "/api/users", body: "{args.input}")
}
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
}
gRPC Subgraphs
Configuration
upstreams:
inventory:
url: http://inventory-service:50051
type: grpc
proto_file: ./protos/inventory.proto
service: inventory.InventoryService
mappings:
- field: Query.inventory
rpc: GetInventory
- field: Mutation.updateStock
rpc: UpdateStock
Proto File
syntax = "proto3";
package inventory;
service InventoryService {
rpc GetInventory (GetInventoryRequest) returns (InventoryResponse);
rpc UpdateStock (UpdateStockRequest) returns (UpdateStockResponse);
}
message GetInventoryRequest {
string product_id = 1;
}
message InventoryResponse {
string product_id = 1;
int32 quantity = 2;
string warehouse = 3;
}
HyperRoute automatically maps protobuf messages to GraphQL types. No code generation step required.
Upstream Configuration
All upstream types (GraphQL, REST, gRPC) share common resilience settings:
upstreams:
users:
url: http://users-api:3000
type: rest # rest | grpc | graphql
timeout: 10s
retry:
max_retries: 3
backoff: exponential
base_delay: 100ms
circuit_breaker:
threshold: 5 # Open after 5 consecutive failures
timeout: 30s # Try again after 30s
connection_pool:
max_connections: 100
idle_timeout: 60s
Connection Affinity
Route related requests to the same subgraph instance for cache locality:
connection_affinity:
enabled: true
strategy: consistent_hash # consistent_hash | sticky_session | round_robin | least_connections
subgraph_configs:
users:
affinity_key: user_id
sessions:
strategy: sticky_session
session_header: "X-Session-Id"
Mixed Federation
The real power is mixing GraphQL, REST, and gRPC subgraphs in a single federated graph:
upstreams:
# GraphQL subgraph
products:
url: http://products:4001/graphql
type: graphql
# REST subgraph
users:
url: http://users-api:3000
type: rest
mappings:
- field: Query.user
method: GET
path: /api/users/{args.id}
# gRPC subgraph
inventory:
url: http://inventory:50051
type: grpc
proto_file: ./protos/inventory.proto
service: inventory.InventoryService
mappings:
- field: Query.inventory
rpc: GetInventory
A single client query can span all three:
query {
product(id: "123") { # From GraphQL subgraph
name
price
seller { # From REST subgraph
name
email
}
inventory { # From gRPC subgraph
quantity
warehouse
}
}
}
HyperRoute's query planner resolves these transparently — the client never knows which backend technology serves each field.
Next Steps
- Federation — Federation directives and entity batching
- Configuration — Full upstream configuration reference
- Deployment — Production deployment patterns