Skip to content
// EFFECT DAYS 2026

OpenRpc unstable

Generates OpenRPC 1.3.2 documents for Effect RPC contracts using the canonical JSON codec. Generation requires neither handlers nor a server and does not install discovery methods or change the transport.

20 exports Since v4.1.3 Source

Annotations

annotations

unstable
Since v4.1.3

Builds a Context containing OpenRPC annotations from the supplied options.

Details

Undefined entries are omitted. False values and empty lists are retained, so method annotations can override group defaults without inheriting their values.

Signature

declare function annotations(options: Pick<OpenRPCMethod, "summary" | "description" | "tags" | "examples" | "deprecated" | "externalDocs" | "errors">): Context<never>

Example Overriding group documentation defaults

import { OpenRpc, Rpc, RpcGroup } from "effect/rpc"
const group = RpcGroup.make(
Rpc.make("Ping").annotateMerge(OpenRpc.annotations({
summary: "Check availability",
deprecated: false,
tags: []
}))
).annotate(OpenRpc.Deprecated, true).annotate(OpenRpc.Tags, [{ name: "legacy" }])
const document = OpenRpc.fromRpcGroup(group, {
info: { title: "Health API", version: "1.0.0" }
})
document.methods[0].deprecated // => false
document.methods[0].tags // => []

Constructors

Since v4.1.3

Generates an OpenRPC 1.3.2 document describing the canonical JSON encoding of the final composed RPC group, including middleware failures.

Gotchas

Schema generation is best-effort, as in OpenAPI; Effect decoding remains the authority for custom predicates and approximated constraints. Structured payloads include x-effect-params-schema with the complete parameter schema, and streams include x-effect-stream; both require Effect-aware tooling. Scalar payloads and schemas that cannot be converted to Draft 7 throw. Errors without literal codes and messages are omitted unless an Errors annotation is set. Void and stream completion results have a JSON null result schema.

Signature

declare function fromRpcGroup<R extends Any>(group: RpcGroup<R>, options: {
readonly info: OpenRPCInfo;
readonly servers?: readonly Array<OpenRPCServer>;
}): OpenRPCSpec

Example Documenting a user lookup

import { Schema } from "effect"
import { OpenRpc, Rpc, RpcGroup } from "effect/rpc"
const users = RpcGroup.make(
Rpc.make("GetUser", {
payload: { id: Schema.String },
success: Schema.Struct({ id: Schema.String, name: Schema.String }),
error: Schema.Struct({ code: Schema.Literal(404), message: Schema.Literal("User not found") })
}).annotate(OpenRpc.Description, "Look up a user by ID")
)
const document = OpenRpc.fromRpcGroup(users, {
info: { title: "Users API", version: "1.0.0" },
servers: [{ name: "production", url: "https://example.com/rpc" }]
})
document.methods[0].params // => [{ name: "id", required: true, schema: { type: "string" } }]
document.methods[0].errors // => [{ code: 404, message: "User not found" }]
JSON.parse(JSON.stringify(document)).openrpc // => "1.3.2"

Example Describing a positional streaming call

import { Schema } from "effect"
import { OpenRpc, Rpc, RpcGroup } from "effect/rpc"
const group = RpcGroup.make(Rpc.make("Values", {
payload: Schema.Tuple([Schema.Int]),
success: Schema.NumberFromString,
stream: true
}))
const method = OpenRpc.fromRpcGroup(group, {
info: { title: "Values API", version: "1.0.0" }
}).methods[0]
method.paramStructure // => "by-position"
method.params.map(({ name }) => name) // => ["0"]
method.result.schema // => { type: "null" }
method["x-effect-stream"]?.itemSchema // => { type: "string" }

Models

OpenRPCContentDescriptor

interface unstable
Since v4.1.3

Named parameter or result with its canonical encoded Draft 7 JSON Schema.

Signature

interface OpenRPCContentDescriptor {
readonly deprecated?: boolean;
readonly description?: string;
readonly name: string;
readonly required?: boolean;
readonly schema: JsonSchema;
readonly summary?: string;
}

OpenRPCEffectStream

interface unstable
Since v4.1.3

Effect-specific metadata for streamed JSON-RPC responses.

Details

Responses marked chunk: true carry a result matching chunkSchema, whose elements match itemSchema. The method's ordinary result descriptor describes terminal completion. Failed exits carry an encoded cause matching causeSchema in error.data. Control methods apply where the transport enables them.

Gotchas

This extension documents Effect's existing protocol; generic OpenRPC clients do not automatically support its streaming or control messages.

Signature

interface OpenRPCEffectStream {
readonly ackMethod: "@effect/rpc/Ack";
readonly causeSchema: JsonSchema;
readonly chunkSchema: JsonSchema;
readonly encoding: "effect-jsonrpc";
readonly errorSchema: JsonSchema;
readonly interruptMethod: "@effect/rpc/Interrupt";
readonly itemSchema: JsonSchema;
}

OpenRPCError

interface unstable
Since v4.1.3

JSON-RPC error metadata. The optional data is an example JSON value, not a JSON Schema; the serializer sends the encoded Effect cause in this field.

Signature

interface OpenRPCError {
readonly code: number;
readonly data?: Json;
readonly message: string;
}

OpenRPCExample

interface unstable
Since v4.1.3

Named encoded JSON value used in a method example.

Signature

interface OpenRPCExample {
readonly description?: string;
readonly name: string;
readonly summary?: string;
readonly value: Json;
}

OpenRPCExamplePairing

interface unstable
Since v4.1.3

Paired named parameters and result illustrating a successful RPC call.

Signature

interface OpenRPCExamplePairing {
readonly description?: string;
readonly name: string;
readonly params: readonly Array<OpenRPCExample>;
readonly result: OpenRPCExample;
readonly summary?: string;
}

OpenRPCExternalDocs

interface unstable
Since v4.1.3

External documentation link attached to a method or tag.

Signature

interface OpenRPCExternalDocs {
readonly description?: string;
readonly url: string;
}

OpenRPCInfo

interface unstable
Since v4.1.3

API identity and optional publication metadata.

Signature

interface OpenRPCInfo {
readonly contact?: {
readonly email?: string;
readonly name?: string;
readonly url?: string;
};
readonly description?: string;
readonly license?: {
readonly name: string;
readonly url?: string;
};
readonly termsOfService?: string;
readonly title: string;
readonly version: string;
}

OpenRPCMethod

interface unstable
Since v4.1.3

JSON-RPC method with named or positional parameters and optional Effect metadata.

Signature

interface OpenRPCMethod {
readonly deprecated?: boolean;
readonly description?: string;
readonly errors?: readonly Array<OpenRPCError>;
readonly examples?: readonly Array<OpenRPCExamplePairing>;
readonly externalDocs?: OpenRPCExternalDocs;
readonly name: string;
readonly params: readonly Array<OpenRPCContentDescriptor>;
readonly paramStructure: "either" | "by-name" | "by-position";
readonly result: OpenRPCContentDescriptor;
readonly summary?: string;
readonly tags?: readonly Array<OpenRPCTag>;
readonly "x-effect-params-schema"?: JsonSchema;
readonly "x-effect-stream"?: OpenRPCEffectStream;
}

OpenRPCServer

interface unstable
Since v4.1.3

Named JSON-RPC endpoint and optional URL template variables.

Signature

interface OpenRPCServer {
readonly description?: string;
readonly name: string;
readonly summary?: string;
readonly url: string;
readonly variables?: Readonly<Record<string, {
readonly default: string;
readonly description?: string;
readonly enum?: readonly Array<string>;
}>>;
}

OpenRPCSpec

interface unstable
Since v4.1.3

OpenRPC document generated from an RPC group.

Signature

interface OpenRPCSpec {
readonly components: {
readonly schemas: Readonly<Record<string, JsonSchema.JsonSchema>>;
};
readonly info: OpenRPCInfo;
readonly methods: readonly Array<OpenRPCMethod>;
readonly openrpc: "1.3.2";
readonly servers?: readonly Array<OpenRPCServer>;
}

OpenRPCTag

interface unstable
Since v4.1.3

Named grouping metadata for an RPC method.

Signature

interface OpenRPCTag {
readonly description?: string;
readonly externalDocs?: OpenRPCExternalDocs;
readonly name: string;
readonly summary?: string;
}

Services

Deprecated

unstable
Since v4.1.3

OpenRPC annotation for marking a method deprecated, overriding the group default.

Signature

declare class Deprecated extends Shape<"effect/rpc/OpenRpc/Deprecated", boolean, this> {
constructor(_: never);
}

Description

unstable
Since v4.1.3

OpenRPC annotation for setting a method description or group default.

Signature

declare class Description extends Shape<"effect/rpc/OpenRpc/Description", string, this> {
constructor(_: never);
}

Errors

unstable
Since v4.1.3

OpenRPC annotation for specifying error metadata. When present, it replaces the error metadata derived from literal code and message fields. Method lists replace group lists.

Signature

declare class Errors extends Shape<"effect/rpc/OpenRpc/Errors", readonly Array<OpenRPCError>, this> {
constructor(_: never);
}

Examples

unstable
Since v4.1.3

OpenRPC annotation for setting encoded call examples, replacing the group default list.

Signature

declare class Examples extends Shape<"effect/rpc/OpenRpc/Examples", readonly Array<OpenRPCExamplePairing>, this> {
constructor(_: never);
}
Since v4.1.3

OpenRPC annotation for setting external documentation or a group default.

Signature

declare class ExternalDocs extends Shape<"effect/rpc/OpenRpc/ExternalDocs", OpenRPCExternalDocs, this> {
constructor(_: never);
}

Summary

unstable
Since v4.1.3

OpenRPC annotation for setting a method summary or group default.

Signature

declare class Summary extends Shape<"effect/rpc/OpenRpc/Summary", string, this> {
constructor(_: never);
}

Tags

unstable
Since v4.1.3

OpenRPC annotation for setting method tags, replacing the group default list.

Signature

declare class Tags extends Shape<"effect/rpc/OpenRpc/Tags", readonly Array<OpenRPCTag>, this> {
constructor(_: never);
}