Transport Bindings
Transport Bindings
Section titled “Transport Bindings”Protocol mapping for HTTP and message queues
Overview
Section titled “Overview”Mesh is transport-agnostic. This document specifies conventions for common transports to ensure interoperability.
Request
Section titled “Request”| Aspect | Convention |
|---|---|
| Method | POST |
| Content-Type | application/json |
| Endpoint | Service-defined (e.g., /mesh, /rpc, /api) |
| Body | JSON-encoded Mesh request |
Response
Section titled “Response”| Aspect | Convention |
|---|---|
| Content-Type | application/json |
| Status Code | 200 OK for all Mesh responses |
| Body | JSON-encoded Mesh response |
Status Codes
Section titled “Status Codes”HTTP status codes MUST NOT indicate Mesh-level errors. All valid Mesh responses return 200 OK, including errors:
HTTP/1.1 200 OKContent-Type: application/json
{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_123", "result": null, "errors": [{ "code": "NOT_FOUND", "message": "Order not found", "retryable": false }]}Exception: Transport-level failures use appropriate HTTP status codes:
| Status | Meaning |
|---|---|
400 Bad Request | Request body is not valid JSON (before Mesh parsing) |
413 Payload Too Large | Request exceeds size limit |
502 Bad Gateway | Upstream service unreachable |
503 Service Unavailable | Service temporarily unavailable |
504 Gateway Timeout | Upstream timeout (transport level, not Mesh deadline) |
These indicate the request never reached the Mesh handler.
Header Mapping
Section titled “Header Mapping”HTTP headers provide metadata for infrastructure components (load balancers, proxies, observability tools) without parsing the JSON body.
Request Headers
Section titled “Request Headers”| Header | Maps To | Description |
|---|---|---|
X-Mesh-Request-Id | id | Request identifier |
X-Mesh-Trace-Id | tracing extension | Distributed trace ID |
X-Mesh-Span-Id | tracing extension | Current span ID |
X-Mesh-Parent-Span-Id | tracing extension | Parent span ID |
X-Mesh-Caller | context.caller | Calling service name |
Trace headers map to the Tracing Extension, not context.
Response Headers
Section titled “Response Headers”| Header | Maps To | Description |
|---|---|---|
X-Mesh-Request-Id | id | Echoed request identifier |
X-Mesh-Duration-Ms | meta.duration | Processing time in milliseconds |
X-Mesh-Node | meta.node | Handling node identifier |
RateLimit-Limit | meta.rate_limit.limit | Rate limit ceiling |
RateLimit-Remaining | meta.rate_limit.remaining | Remaining requests |
RateLimit-Reset | meta.rate_limit.resets_in | Seconds until window reset |
RateLimit-Policy | — | Policy identifier (optional) |
Rate limit headers follow IETF draft-ietf-httpapi-ratelimit-headers.
- Headers are OPTIONAL — the JSON body is authoritative
- Servers SHOULD set headers for observability
- Clients SHOULD set trace headers for propagation
- When headers and body conflict, body takes precedence
Format differences: Headers use string representations (milliseconds for duration). The JSON body uses structured objects. Servers MUST convert between formats when mapping headers to body.
Example
Section titled “Example”POST /mesh HTTP/1.1Host: orders-api.internalContent-Type: application/jsonX-Mesh-Request-Id: req_xyz789X-Mesh-Trace-Id: tr_8f3a2b1cX-Mesh-Span-Id: sp_4d5e6fX-Mesh-Caller: checkout-service
{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_xyz789", "call": { "function": "orders.create", "version": "1", "arguments": { "customer_id": 42 } }, "context": { "caller": "checkout-service" }, "extensions": [ { "urn": "urn:mesh:ext:deadline", "options": { "value": 5, "unit": "second" } }, { "urn": "urn:mesh:ext:tracing", "options": { "trace_id": "tr_8f3a2b1c", "span_id": "sp_4d5e6f" } } ]}HTTP/1.1 200 OKContent-Type: application/jsonX-Mesh-Request-Id: req_xyz789X-Mesh-Duration-Ms: 127X-Mesh-Node: orders-api-2RateLimit-Limit: 1000RateLimit-Remaining: 847RateLimit-Reset: 45
{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_xyz789", "result": { "order_id": 12345 }, "meta": { "duration": { "value": 127, "unit": "millisecond" }, "node": "orders-api-2", "rate_limit": { "limit": 1000, "remaining": 847, "resets_in": { "value": 45, "unit": "second" } } }}Timeouts
Section titled “Timeouts”HTTP clients SHOULD configure connection and read timeouts:
| Timeout | Recommendation |
|---|---|
| Connection | 5 seconds |
| Read | Mesh deadline + buffer (e.g., deadline + 1s) |
The read timeout SHOULD exceed the Mesh deadline to allow the server to return a DEADLINE_EXCEEDED error rather than the connection being cut.
Keep-Alive
Section titled “Keep-Alive”HTTP/1.1 connections SHOULD use keep-alive for efficiency. HTTP/2 is RECOMMENDED for high-throughput scenarios as it provides:
- Connection multiplexing
- Header compression
- Reduced latency
Message Queues
Section titled “Message Queues”Overview
Section titled “Overview”Message queues enable asynchronous request processing. Common implementations: RabbitMQ, Redis Streams, Amazon SQS.
Message Structure
Section titled “Message Structure”| Aspect | Convention |
|---|---|
| Body | JSON-encoded Mesh request |
| Content-Type | application/json |
| Correlation ID | Mesh id field |
| Reply-To | Queue for response (if expecting reply) |
Property Mapping
Section titled “Property Mapping”Request Message Properties
Section titled “Request Message Properties”| Property | Maps To | Description |
|---|---|---|
correlation_id | id | Request identifier |
reply_to | — | Response queue name |
expiration | deadline extension | Message TTL in milliseconds |
headers.trace_id | tracing extension | Distributed trace ID |
headers.span_id | tracing extension | Current span ID |
headers.caller | context.caller | Calling service |
Trace headers map to the Tracing Extension, not context.
Response Message Properties
Section titled “Response Message Properties”| Property | Maps To | Description |
|---|---|---|
correlation_id | id | Echoed request identifier |
headers.duration_ms | meta.duration | Processing time |
headers.node | meta.node | Handling node |
Deadline Handling
Section titled “Deadline Handling”Message TTL SHOULD reflect the Mesh deadline:
message_ttl = deadline_value (converted to ms)When a message expires before processing:
- Queue MAY move it to dead letter queue
- Consumer SHOULD NOT process expired messages
- If processed, server SHOULD return
DEADLINE_EXCEEDED
Request-Response Pattern
Section titled “Request-Response Pattern”For standard requests expecting responses:
- Client publishes request to service queue
- Client waits on reply queue (from
reply_to) - Server processes request
- Server publishes response to reply queue
- Client receives response, matched by
correlation_id
┌──────────┐ request ┌───────────────┐│ Client │ ───────────────► │ Service Queue │└──────────┘ └───────────────┘ ▲ │ │ ▼ │ ┌───────────┐ │ response │ Server │ └─────────────────────── │ │ (reply queue) └───────────┘Dead Letter Handling
Section titled “Dead Letter Handling”Failed messages SHOULD be routed to a dead letter queue when:
- Message expires (TTL exceeded)
- Processing fails after max retries
- Message cannot be parsed
Dead letter queues enable:
- Debugging failed requests
- Manual retry/reprocessing
- Alerting on failure patterns
Example: RabbitMQ
Section titled “Example: RabbitMQ”Publishing Request:
$channel->basic_publish( new AMQPMessage( json_encode($meshRequest), [ 'content_type' => 'application/json', 'correlation_id' => $meshRequest['id'], 'reply_to' => 'responses.checkout-service', 'expiration' => '5000', // 5 seconds 'headers' => new AMQPTable([ 'trace_id' => $meshRequest['context']['trace_id'], 'span_id' => $meshRequest['context']['span_id'], 'caller' => 'checkout-service', ]), ] ), '', 'orders-api');Publishing Response:
$channel->basic_publish( new AMQPMessage( json_encode($meshResponse), [ 'content_type' => 'application/json', 'correlation_id' => $meshResponse['id'], 'headers' => new AMQPTable([ 'duration_ms' => 127, 'node' => 'orders-api-2', ]), ] ), '', $replyTo);Unix Sockets
Section titled “Unix Sockets”For local inter-process communication:
| Aspect | Convention |
|---|---|
| Protocol | Stream socket |
| Framing | Length-prefixed JSON |
| Path | Service-defined (e.g., /var/run/mesh/orders.sock) |
Message Framing
Section titled “Message Framing”Each message is prefixed with a 4-byte big-endian length:
┌──────────────┬─────────────────────┐│ Length (4B) │ JSON Payload │└──────────────┴─────────────────────┘This allows efficient message boundary detection without delimiter scanning.
Implementation Notes
Section titled “Implementation Notes”Content Negotiation
Section titled “Content Negotiation”Mesh uses JSON exclusively. Servers SHOULD reject requests with unsupported content types:
HTTP/1.1 415 Unsupported Media TypeContent-Type: application/json
{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": null, "result": null, "errors": [{ "code": "INVALID_REQUEST", "message": "Content-Type must be application/json", "retryable": false }]}Request Size Limits
Section titled “Request Size Limits”Servers SHOULD enforce request size limits:
| Limit | Recommendation |
|---|---|
| Maximum request body | 1 MB |
| Maximum header size | 8 KB |
Exceeded limits return 413 Payload Too Large (HTTP) or reject the message (queues).
Compression
Section titled “Compression”Compression is handled at the transport layer:
- HTTP: Use standard
Accept-Encoding/Content-Encodingheaders (gzip, br) - Queues: Configure at broker level or use compressed message body
Mesh does not specify compression — it is an infrastructure concern.
Authentication
Section titled “Authentication”Authentication is an implementation concern handled at the transport layer. Mesh does not specify authentication mechanisms but provides guidance for common patterns.
HTTP Authentication
Section titled “HTTP Authentication”Bearer Tokens
Section titled “Bearer Tokens”Use standard Authorization header for token-based authentication:
POST /mesh HTTP/1.1Host: orders-api.internalContent-Type: application/jsonAuthorization: Bearer eyJhbGciOiJIUzI1NiIs...Servers validate the token before processing the Mesh request. Invalid tokens return transport-level errors:
HTTP/1.1 401 UnauthorizedWWW-Authenticate: Bearer realm="mesh-api"
{ "error": "invalid_token", "error_description": "Token has expired"}Note: This is a transport-level error, not a Mesh error. The request never reached the Mesh handler.
API Keys
Section titled “API Keys”For service-to-service authentication:
POST /mesh HTTP/1.1Host: orders-api.internalContent-Type: application/jsonX-API-Key: sk_live_abc123xyzMutual TLS (mTLS)
Section titled “Mutual TLS (mTLS)”For internal service mesh authentication, use mutual TLS at the transport layer. The client presents a certificate that identifies the calling service:
┌─────────────┐ mTLS ┌─────────────┐│ Service A │ ◄────────────► │ Service B ││ (client) │ cert: A │ (server) │└─────────────┘ └─────────────┘With mTLS, the server can populate context.caller from the client certificate’s Common Name (CN) or Subject Alternative Name (SAN).
Message Queue Authentication
Section titled “Message Queue Authentication”For message queues, authentication typically occurs at connection time:
- RabbitMQ: Username/password or x509 certificates
- Amazon SQS: IAM roles and policies
- Redis Streams: ACL authentication
The queue broker validates credentials before allowing message publication or consumption.
Authorization Context
Section titled “Authorization Context”After transport-level authentication, authorization data should be propagated via context:
{ "context": { "caller": "checkout-service", "tenant_id": "tenant_acme", "user_id": "user_42", "scopes": ["orders:read", "orders:write"] }}This enables:
- Multi-tenant isolation (filter by
tenant_id) - User-level authorization (validate
user_idhas access) - Scope-based access control (check
scopesfor permission)
Internal vs External APIs
Section titled “Internal vs External APIs”| Aspect | Internal (service-to-service) | External (client-facing) |
|---|---|---|
| Authentication | mTLS, API keys | OAuth 2.0, JWT |
| Trust level | High (verified service) | Low (validate everything) |
| Rate limiting | Per-service quotas | Per-user/tenant quotas |
| Context source | Propagated from upstream | Extracted from token |
Security Recommendations
Section titled “Security Recommendations”- Always use TLS — Never send Mesh requests over unencrypted connections
- Validate at the edge — Authenticate external requests at API gateway
- Propagate identity — Pass authenticated identity via context
- Principle of least privilege — Scope service permissions narrowly
- Rotate credentials — Use short-lived tokens where possible