oRPC
background

Middleware

The powerful and flexible way to reuse logic across procedures in oRPC.

Introduction

Middleware in oRPC is both powerful and flexible, enabling you to accomplish many tasks efficiently.

import { ,  } from '@orpc/server'
 
export type  = { ?: { : string } }
 
export const  /** public access */ = .<>()
 
const  = .(async (, , ) => {
    if (!.) {
        throw new ({
            : 'UNAUTHORIZED',
            : 'You need to log in first',
        })
    }
 
    const  = await .({
        : {
            : .,
        }
    })
 
    // Do something on success
 
    return 
})
 
// Now every procedure or router defined in this oRPC will be protected by authMiddleware
export const  /** require authed */ = .()

Typed Input

Middleware can expect specific input types, opening up many possibilities:

import { ,  } from '@orpc/server'
import {  } from 'zod' 
 
const  = 
    .(async (: {: string}, , ) => { 
        // Now you can specify the input type for middleware
        return .({})
    })
 

    .(.({ : .() }))
    .(canEditPostMiddleware) // ❗ mismatched input type
Argument of type 'DecoratedMiddleware<Record<string, unknown> | undefined, undefined, { id: string; }, any>' is not assignable to parameter of type 'Middleware<Record<string, unknown> | undefined, undefined, { postId: string; }, unknown>'. Types of parameters 'input' and 'input' are incompatible. Property 'id' is missing in type '{ postId: string; }' but required in type '{ id: string; }'.
.(, () => ({ : . })) // ✅ map the input to match expected type

Concatenation

You can merge or extend middlewares using concatenation:

import {  } from '@orpc/server'
 
const  = .(async (, , ) => .({}))
const  = .(async (, , ) => .({}))
 
const  = .() // Merge middleware
 
const  = .((, , ) => .({})) // Extend middleware

Extra Context

Extra context is created by middlewares and automatically merges with the global context, enhancing developer experience:

import { ,  } from '@orpc/server'
 
type  = {
    ?: {
        : string
    }
}
 
export const  = .<>()
 
// Any procedure using this middleware will infer context.user as NonNullable<typeof context['user']>
const  = 
    .(async (, , ) => {
        if (!.) {
            throw new ({ : 'UNAUTHORIZED' })
        }
 
        return .({
            : {
                : .
            }
        })
    })
 
export const  = 
    .()
    .((, , ) => {
 
        const : <typeof ['user']> = .
 
        return .({
            : {
                : 'hi'
            }
        })
    })
    .(async (, , ) => {
        
        const : <typeof ['user']> = .
        const : string = .
 
    })

Output

Middleware can directly output data to the client without invoking the handler. This is particularly useful for scenarios such as caching responses or pre-processing the output before sending it to the client.

import {  } from '@orpc/server'
 
const  = new <string, unknown>()
 
const  = .(async (, , ) => {
    const  = ..('/') + .() /* stringify is not ideal, but it's just an example */
 
    if (.()) {
        return .(.())
    }
 
    const  = await .({})
    .(, .)
    return 
})

On this page