10.1 Services
@v(2) pub(api) service Users {
@readonly @cache(ttl: USER_CACHE_TTL)
rpc get(id: UserId) -> User | NotFound
@idempotent(key: r => r.requestId) @retry(STD_RETRIES)
rpc create(requestId: RequestId, name: Name, email: Email?) -> User
@resumable
rpc watch(id: UserId) -> stream<UserEvent>
}
impl Users {
dep db: Db
rpc get(id) { db.find(User, id) ?? fail NotFound{ what: "user" } }
rpc create(requestId, name, email) { … }
rpc watch(id) { UserEvents.subscribe(key: id) }
}- A
servicedeclares a contract: a set ofrpcs with named parameters and a result type. The parameters form the request message, the result the response message (tags per §9.2). - A program MUST contain exactly one
implfor each service, unless it is declaredextern service(a client of an external service, §16.3). - In an
implthe parameter and result types MAY be omitted — they are taken from theservice. The handler's effects are not restricted. - The handler's dependencies are declared with
dep name: Type(§12.7). - Result errors are transmitted as typed gRPC error details. The status code comes from
@grpc_status(code)on the error type,FAILED_PRECONDITIONby default.NetError↔ statuses:Timeout—DEADLINE_EXCEEDED,Unavailable—UNAVAILABLE,Cancelled—CANCELLED,AccessDenied—PERMISSION_DENIED/UNAUTHENTICATED,ProtocolError— the rest.
Calling:
| Form | Routing |
|---|---|
Users.get(id) | through the cluster (§12.3): locally if the node serves Users, otherwise over the network |
Users.at(node).get(id) | to a specific node of the cluster |
Users.connect(addr, tls: opts) | a client to an external address; returns Client<Users> |
The context ctx is available in the handler and is propagated to outgoing calls: ctx.caller: Principal, ctx.deadline, ctx.traceId, ctx.meta: Map<str, str>, ctx.node.
Related diagnostics
duplicate-impl, impl-signature-mismatch, missing-impl, missing-rpc-impl, unknown-rpc
See also
Source: docs/spec/oxl-standard.en.md