RPC Specification
Overview¶
RPC services in VDL are modeled with annotations on core language declarations.
@rpc marks a service container on a type declaration. @proc and @stream mark service operations on type members.
Schema Modeling¶
@rpc
type Users {
@proc
getUser {
input {
userId string
}
output {
id string
email string
}
}
@stream
userEvents {
input {
userId string
}
output {
event string
at datetime
}
}
}
The RPC model uses these structural rules.
@rpcis attached to atypedeclaration.@procand@streamare attached to members inside the@rpctype.- Operation members are regular fields with inline object types.
inputandoutputare regular field names whose types are inline objects.
Because input and output are inline object fields, they support standard language features, including spreads and docstrings.
Request Lifecycle¶
This section defines the end-to-end data flow for both procedure calls and stream subscriptions. It covers URL structure, JSON payloads, connection behavior, and error handling. The behavior is language-agnostic and applies to official generators.
Procedures (Request-Response)¶
Procedures follow a request-response model over HTTP and complete within a single HTTP transaction.
1. Client Invocation¶
Application code invokes a generated procedure client function. The generated client builds the HTTP request.
2. HTTP Request¶
The client sends an HTTP POST request.
- Method:
POST - URL Structure:
<baseURL>/<RPCName>/<ProcedureName> - Example:
https://api.example.com/rpc/Users/getUser - Headers:
Content-Type: application/jsonAccept: application/json- Body: JSON-encoded procedure input.
3. Server Handling¶
The server processes a procedure request in three stages.
- Routing: The URL path is mapped to an RPC service and procedure handler.
- Deserialization and Validation: The JSON body is decoded and validated.
- Handler Execution: The user-defined handler executes with validated input.
VDL middleware hooks can run custom logic such as authentication, authorization, validation, logging, and metrics.
4. Server Response¶
The handler returns either output data or error data. The server serializes the result into a JSON envelope.
5. HTTP Response¶
The server returns one HTTP response.
- Status Code:
200 OKfor successfully processed requests. Application-level success or failure is represented by the response envelope. - Headers:
Content-Type: application/json - Body:
Success envelope:
{
"ok": true,
"output": {
"id": "user-123",
"email": "[email protected]"
}
}
Failure envelope:
{
"ok": false,
"error": {
"message": "User not found.",
"category": "NotFound",
"code": "USER_NOT_FOUND",
"details": {
"userId": "user-123"
}
}
}
error fields:
message(string): human-readable descriptioncategory(string, optional): error classcode(string, optional): machine-readable codedetails(object, optional): structured context
6. Client Handling¶
The generated client decodes the envelope and returns output or error to application code.
- Deserialization: parse JSON body.
- Envelope handling:
ok: truereturnsoutput.ok: falsereturnserror.- Resilience: transport failures can use retry policies such as exponential backoff, depending on client configuration.
Streams (Server-Sent Events)¶
Streams use Server-Sent Events (SSE) with a persistent connection so servers can push multiple events over time.
1. Client Subscription¶
Application code subscribes through the generated stream client.
2. HTTP Request (Connection)¶
The client opens the stream with a POST request.
- Method:
POST - URL Structure:
<baseURL>/<RPCName>/<StreamName> - Example:
https://api.example.com/rpc/Chat/NewMessage - Headers:
Accept: text/event-streamContent-Type: application/json- Body: JSON-encoded stream input.
3. Server Handling (Connection)¶
The server validates input and initializes the SSE channel.
- Validation: invalid input returns a single JSON error response.
- Connection setup:
- Status
200 OK Content-Type: text/event-streamCache-Control: no-cacheConnection: keep-alive- Handler execution: stream handler runs with an
emitfunction.
Middleware hooks are available for cross-cutting behavior in stream flows.
4. Event Emission¶
Handlers call emit to push events. Each emitted event is serialized and written as SSE data.
- JSON payloads must be single-line for SSE framing safety.
- Newline-sensitive formatting is handled before transmission.
Success event:
Error event:
5. Keep-Alive (Ping Events)¶
Servers send periodic SSE comments to keep connections alive.
- Format:
: ping\n\n - Interval: server-configurable (commonly 30 seconds)
- Client behavior: ignored by generated clients and not surfaced to application code
6. Client Handling (Event Loop)¶
The client processes stream events continuously.
- Parse SSE frames.
- Ignore comment ping frames.
- Deserialize JSON payloads.
- Deliver
outputorerrorenvelopes to application code.
7. Stream Termination¶
A stream can end by client cancellation, handler completion, or network interruption.
Generated clients may reconnect automatically with configurable retry behavior, re-sending the original subscription request when applicable.