Silgi
Integrations

Fastify

Mount Silgi as a Fastify plugin — run RPC and REST routes on the same server.

Silgi has a built-in serve() function that creates its own HTTP server. But if you already have a Fastify application with REST routes, middleware, and plugins, you can add Silgi alongside everything else using the Fastify adapter.

When to use this

ApproachWhen
s.serve(router)New project, Silgi-only server
silgiFastify(router)Adding RPC to an existing Fastify app

Setup

Install Fastify

npm install fastify

Create your Silgi router

If you haven't defined a router yet, see the Getting Started guide. You need a router object — the same one you'd pass to s.serve().

Register the plugin

import  from 'fastify'
import {  } from 'silgi/fastify'
import {  } from './router'

const  = ()

// Your existing REST routes
.('/api/health', async () => ({ : 'rest' }))

// Silgi RPC under /rpc prefix
.(
  (, {
    : () => ({
      : .user,
      : .ip,
    }),
  }),
  { : '/rpc' },
)

.({ : 3000 })

Each procedure becomes a POST route under the prefix:

POST /rpc/health
POST /rpc/users/list
POST /rpc/users/create

Context from Fastify

The context option receives the Fastify request object. Use it to bridge Fastify's auth plugins, IP detection, and headers into Silgi's context:

silgiFastify(appRouter, {
  : () => ({
    : .user, // from @fastify/jwt or similar
    : .ip, // client IP
    : .headers, // raw headers
  }),
})

If you don't provide a context function, an empty object is used.

Content negotiation

Content negotiation works automatically. If the client sends Accept: application/x-msgpack, the Fastify adapter responds with MessagePack. Same for devalue. JSON is the default.

Fastify's built-in JSON parser handles request body parsing. The adapter only needs to encode the response.

Fastify's schema-based serialization is not used here — Silgi has its own compiled serializers. Request bodies are parsed by Fastify, but response encoding is handled by Silgi for consistency with serve() and handler().

Error handling

Errors from guards, wraps, and resolvers are caught and returned as JSON responses with the appropriate status code. Validation errors return 400, SilgiError returns its defined status, and unexpected errors return 500.

The error format is the same as serve() and handler():

{
  "code": "NOT_FOUND",
  "status": 404,
  "message": "Not Found"
}

What's next?

  • Serverserve() for standalone Silgi servers
  • Client — connect to your Fastify-hosted Silgi API
  • Protocols — JSON, MessagePack, and devalue wire formats

On this page