The screenshot API for developers -
Try ScreenshotOne
Skip to content

Fetch API Adapter ​

oRPC supports the Fetch API for both servers and clients.

Server Usage ​

ts
import { RPCHandler } from '@orpc/server/fetch'
import { CORSPlugin } from '@orpc/server/plugins'
import { onError } from '@orpc/server'

const handler = new RPCHandler(router, {
  plugins: [
    new CORSHandlerPlugin()
  ],
  interceptors: [
    onError((error) => {
      console.error(error)
    }),
  ],
})

export async function fetch(request: Request): Promise<Response> {
  const { matched, response } = await handler.handle(request, {
    prefix: '/rpc',
    context: {} // Provide initial context if needed
  })

  if (matched) {
    return response
  }

  return new Response('Not found', { status: 404 })
}
ts
import { OpenAPIHandler } from '@orpc/openapi/fetch'
import { CORSPlugin } from '@orpc/server/plugins'
import { onError } from '@orpc/server'

const handler = new OpenAPIHandler(router, {
  plugins: [
    new CORSHandlerPlugin()
  ],
  interceptors: [
    onError((error) => {
      console.error(error)
    }),
  ],
})

export async function fetch(request: Request): Promise<Response> {
  const { matched, response } = await handler.handle(request, {
    prefix: '/api',
    context: {} // Provide initial context if needed
  })

  if (matched) {
    return response
  }

  return new Response('Not found', { status: 404 })
}

INFO

The actual usage of fetch depends on the runtime environment or library you use:

ts
Bun.serve({
  fetch,
})
ts
export default {
  fetch,
}
ts
Deno.serve(fetch)
ts
import { handle } from 'hono/aws-lambda'

export const handler = handle({ fetch })

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'],
})

Client Usage ​

ts
import { RPCLink } from '@orpc/client/fetch'
import { onError } from '@orpc/client'

const link = new RPCLink({
  origin: 'https://api.example.com', // accepts async function, defaults to current origin
  url: '/rpc', // accepts async function
  headers: { authorization: 'bearer token' }, // accept async function
  interceptors: [
    onError((error) => {
      console.error(error)
    }),
  ],
  fetch: (request, init) => { // <- override fetch if needed
    return globalThis.fetch(request, {
      ...init,
      credentials: 'include', // Include cookies on cross-origin requests
    })
  },
})
ts
import { OpenAPILink } from '@orpc/openapi/fetch'
import { onError } from '@orpc/client'

const link = new OpenAPILink(contract, {
  origin: 'https://api.example.com', // accepts async function, defaults to current origin
  url: '/rpc', // accepts async function
  headers: { authorization: 'bearer token' }, // accept async function
  interceptors: [
    onError((error) => {
      console.error(error)
    }),
  ],
  fetch: (request, init) => { // <- override fetch if needed
    return globalThis.fetch(request, {
      ...init,
      credentials: 'include', // Include cookies on cross-origin requests
    })
  },
})

INFO

The examples above only show how to configure the link. For examples of creating a typesafe client, see RPC Link and OpenAPI Link.

Event Stream Options ​

You can configure how an AsyncIteratorObject is streamed to the client using the toFetchResponse.eventStream options when creating the handler.

ts
const handler = new OpenAPIHandler(router, {
  toFetchResponse: {
    eventStream: {
      initialComment: {
        /**
         * If true, an initial comment is sent immediately upon stream start to flush headers.
         * This allows the receiving side to establish the connection without waiting for the first event.
         *
         * @default true
         */
        enabled: true,
        /**
         * The content of the initial comment sent upon stream start. Must not include newline characters.
         *
         * @default ''
         */
        comment: '',
      },
      keepAlive: {
        /**
         * If true, a ping comment is sent periodically to keep the connection alive.
         *
         * @default true
         */
        enabled: true,
        /**
         * Interval (in milliseconds) between ping comments sent after the last event.
         *
         * @default 5000
         */
        interval: 5000,
        /**
         * The content of the ping comment. Must not include newline characters.
         *
         * @default ''
         */
        comment: '',
      },
      /**
       * If true, a `close` event is sent even when the iterator completes with `undefined`.
       * When the iterator returns a value, a `close` event is always emitted regardless of this setting.
       *
       * @default true
       */
      emptyCloseEventEnabled: true,
    },
  },
})

INFO

You can also configure how an AsyncIteratorObject is streamed from client to server using toFetchRequest.eventStream options when creating the link.

Released under the MIT License.