FAQ
Frequently asked questions and design decisions
Why doesn’t Mesh support notifications?
Section titled “Why doesn’t Mesh support notifications?”Many RPC protocols (like JSON-RPC 2.0) support “notifications” — requests without an id field where the server processes the request but never sends a response. Mesh intentionally omits this feature.
The Problem with Notifications
Section titled “The Problem with Notifications”Notifications provide no feedback. The caller cannot know:
- Did the function exist?
- Were the arguments valid?
- Did processing succeed or fail?
- Was the request even received?
For internal microservice communication, this lack of feedback creates reliability problems:
// A notification to get a user makes no sense{ "protocol": { "name": "mesh", "version": "0.1.0" }, "call": { "function": "users.get", "version": "1", "arguments": { "id": 42 } }}// Where does the user data go? Nowhere.The protocol would allow structurally valid requests that are semantically nonsensical.
Better Alternatives
Section titled “Better Alternatives”For “fire and forget” with tracking:
Use the async extension. The server returns immediately with an operation ID, and the caller can check status later if needed:
// Request{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_001", "call": { "function": "reports.generate", "version": "1", "arguments": { "type": "annual" } }, "extensions": [ { "urn": "urn:mesh:ext:async", "options": { "preferred": true } } ]}
// Response (immediate){ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_001", "result": null, "extensions": [ { "urn": "urn:mesh:ext:async", "data": { "operation_id": "op_xyz789", "status": "processing", "poll": { "function": "mesh.operation.status", "version": "1", "arguments": { "operation_id": "op_xyz789" } }, "retry_after": { "value": 5, "unit": "second" } } } ]}For fast acknowledgment:
Functions can validate, queue work, and return immediately:
// Response in <5ms{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_001", "result": { "queued": true, "job_id": "job_abc123" }}This provides the same speed as notifications, plus confirmation that the request was valid and accepted.
For event emission:
Use message queues directly. If you’re emitting events without needing Mesh’s request/response semantics, the queue transport is more appropriate than wrapping events in Mesh protocol overhead.
How does Mesh handle long-running operations?
Section titled “How does Mesh handle long-running operations?”Mesh provides first-class support for asynchronous operations. See Async for full details.
Quick Overview
Section titled “Quick Overview”Request async processing:
{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_001", "call": { "function": "exports.generate", "version": "1", "arguments": { "format": "csv" } }, "extensions": [ { "urn": "urn:mesh:ext:async", "options": { "preferred": true } } ]}Server accepts and returns operation ID:
{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_001", "result": null, "extensions": [ { "urn": "urn:mesh:ext:async", "data": { "operation_id": "op_xyz789", "status": "processing", "poll": { "function": "mesh.operation.status", "version": "1", "arguments": { "operation_id": "op_xyz789" } } } } ]}Poll for status:
{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_poll", "call": { "function": "mesh.operation.status", "version": "1", "arguments": { "operation_id": "op_xyz789" } }}Get result when complete:
{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_poll", "result": { "operation_id": "op_xyz789", "status": "completed", "result": { "download_url": "https://..." } }}System Functions for Operations
Section titled “System Functions for Operations”mesh.operation.status— Check operation statusmesh.operation.cancel— Cancel a pending operationmesh.operation.list— List operations for the caller
See System Functions for details.
Why per-function versioning instead of API versioning?
Section titled “Why per-function versioning instead of API versioning?”Traditional REST APIs version the entire API: /api/v1/, /api/v2/. Mesh versions each function independently.
The Problem with API Versioning
Section titled “The Problem with API Versioning”When you version the entire API, unrelated changes force version bumps everywhere:
/api/v1/orders ← Unchanged, but stuck at "v1"/api/v1/users ← The actual breaking change/api/v1/products ← Unchanged, but stuck at "v1"Consumers must upgrade everything when they only needed one change. Teams must coordinate releases across unrelated domains.
Per-Function Versioning
Section titled “Per-Function Versioning”orders.create@1 ← Untouchedusers.get@2 ← Evolved independentlyproducts.list@1 ← UntouchedBenefits:
- Teams evolve functions without coordinating releases
- Consumers upgrade function-by-function
- Deprecation is surgical: sunset
orders.create@1, not “all of v1” - No version sprawl where everything is “v7” but 90% unchanged
See Versioning for full details.
Why is the id field a string, not a number?
Section titled “Why is the id field a string, not a number?”JSON numbers have precision limits. JavaScript (and many JSON parsers) use IEEE 754 double-precision floats, which can only safely represent integers up to 2^53.
// JavaScript precision lossJSON.parse('{"id": 9007199254740993}')// { id: 9007199254740992 } — Wrong!String IDs avoid this entirely and support richer formats:
- UUID v4:
"550e8400-e29b-41d4-a716-446655440000" - Prefixed:
"req_abc123xyz" - ULID:
"01ARZ3NDEKTSV4RRFFQ69G5FAV"
Why does Mesh use error/errors instead of HTTP status codes?
Section titled “Why does Mesh use error/errors instead of HTTP status codes?”HTTP status codes are transport-level. Mesh is transport-agnostic — it works over HTTP, message queues, or any other transport.
Additionally, HTTP status codes are ambiguous:
- Is
404“endpoint not found” or “resource not found”? - Is
500a Mesh error or a proxy error? - Is
503the service or a load balancer?
Mesh uses:
- HTTP
200for all Mesh responses (the transport succeeded) error/errorsfield for Mesh-level errors with explicit codes
Transport-level errors (502, 503, 504) indicate the request never reached Mesh.
See Errors for the full error specification.