Skip to content

RPC Protocol

The RPC protocol is a lightweight protocol for remote procedure calls. It supports more native types than plain JSON and is used by RPC Handler and RPC Link.

Serializer

Most of the protocol's flexibility comes from its serializer. In addition to JSON-compatible values, it supports native types such as Date, BigInt, RegExp, URL, Set, Map, Blob, File, AsyncIteratorObject, and ReadableStream<Uint8Array>. To learn more, including how to extend it, see RPC Serializer.

WARNING

To better support Blob, File, and ReadableStream<Uint8Array> at the root level in cross-origin scenarios, extend your CORS allowlist to allow clients to send and receive the Content-Disposition and Standard-Server headers. Learn more in the Standard Server documentation. If you use the CORS Plugin, include them in allowHeaders and exposeHeaders:

ts
const cors = new CORSHandlerPlugin({
  allowHeaders: ['Content-Disposition', 'Standard-Server'],
  exposeHeaders: ['Content-Disposition', 'Standard-Server'],
})

Routing

The request pathname identifies which procedure to call.

bash
curl https://example.com/rpc/planet/create

This calls the planet.create procedure when /rpc is the prefix:

ts
const router = {
  planet: {
    create: os.handler(() => {}) 
  }
}

Sending Input

You can use any HTTP method. Send input in the query string or request body, depending on the method.

INFO

Request payloads depend on the serializer and are not plain JSON. Learn more in RPC Serializer Format.

Query String

ts
const url = new URL('https://example.com/rpc/planet/create')

url.searchParams.append('data', JSON.stringify({
  json: {
    name: 'Earth',
    detached_at: '2022-01-01T00:00:00.000Z'
  },
  meta: [['date', 'detached_at']]
}))

const response = await fetch(url)

Request Body

bash
curl -X POST https://example.com/rpc/planet/create \
  -H 'Content-Type: application/json' \
  -d '{
    "json": {
      "name": "Earth",
      "detached_at": "2022-01-01T00:00:00.000Z"
    },
    "meta": [["date", "detached_at"]]
  }'

With Files

ts
const form = new FormData()

form.set('data', JSON.stringify({
  json: {
    name: 'Earth',
    thumbnail: {},
    images: [{}],
  },
  maps: [['thumbnail'], ['images', 0]]
}))

form.set('0', new Blob([''], { type: 'image/png' }))
form.set('1', new Blob([''], { type: 'image/png' }))

const response = await fetch('https://example.com/rpc/planet/create', {
  method: 'POST',
  body: form
})

Success Response

http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "json": {
    "id": "1",
    "name": "Earth",
    "detached_at": "2022-01-01T00:00:00.000Z"
  },
  "meta": [["bigint", "id"], ["date", "detached_at"]]
}

A successful response uses an HTTP status code in the 200-299 range and returns the procedure output.

INFO

Response bodies depend on the serializer and are not plain JSON. Learn more in RPC Serializer Format.

Error Response

http
HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "json": {
    "defined": false,
    "inferable": false,
    "code": "INTERNAL_SERVER_ERROR",
    "message": "Internal server error",
    "data": {
      "id": "1234567890"
    }
  },
  "meta": [["bigint", "data", "id"]]
}

An error response uses an HTTP status code in the 400-599 range and returns an ORPCError object.

INFO

Response bodies depend on the serializer and are not plain JSON. Learn more in RPC Serializer Format.

Released under the MIT License.