Skip to content

Commit a5c2886

Browse files
authored
docs: "Dedupe Middleware" (#232)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Documentation** - Added a new "Best Practices" section in the sidebar with a link to updated guidelines. - Introduced a guide titled "Dedupe Middleware" that explains how to optimize middleware execution for better performance and reliability. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 8e347ae commit a5c2886

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

apps/content/.vitepress/config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ export default defineConfig({
132132
{ text: 'Svelte', link: '/docs/tanstack-query/svelte' },
133133
],
134134
},
135+
{
136+
text: 'Best Practices',
137+
collapsed: true,
138+
items: [
139+
{ text: 'Dedupe Middleware', link: '/docs/best-practices/dedupe-middleware' },
140+
],
141+
},
135142
{
136143
text: 'Advanced',
137144
collapsed: true,
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
Title: Dedupe Middleware
3+
Description: Improve performance and ensure safety when running oRPC middleware multiple times.
4+
---
5+
6+
# Dedupe Middleware
7+
8+
This guide explains how to optimize your [middleware](/docs/middleware) so it remains fast, efficient, and safe even when executed multiple times.
9+
10+
## Problem
11+
12+
When a procedure [calls](/docs/client/server-side#using-the-call-utility) another procedure, overlapping middleware might be applied in both.
13+
14+
Similarly, when using `.use(auth).router(router)`, some procedures inside `router` might already include the `auth` middleware.
15+
16+
:::warning
17+
This duplication can lead to repeated execution of middleware, causing unexpected behaviors or performance issues, especially if the middleware is resource-intensive.
18+
:::
19+
20+
## Solution
21+
22+
The solution is to use the `context` to track which middleware has already run. For example:
23+
24+
```ts twoslash
25+
import { os } from '@orpc/server'
26+
declare function connectDb(): Promise<'a_fake_db'>
27+
// ---cut---
28+
const dbProvider = os
29+
.$context<{ db?: Awaited<ReturnType<typeof connectDb>> }>()
30+
.middleware(async ({ context, next }) => {
31+
if (context.db) {
32+
return next({ context: { db: context.db } })
33+
}
34+
35+
const db = await connectDb()
36+
return next({ context: { db } })
37+
})
38+
```
39+
40+
In this example, the `dbProvider` middleware checks if a database connection already exists in the `context`. If it does, it simply passes the context along; if not, it establishes a connection and saves it in the `context`.
41+
42+
This middleware can now be safely applied multiple times:
43+
44+
```ts twoslash
45+
import { call, os } from '@orpc/server'
46+
47+
declare function connectDb(): Promise<'a_fake_db'>
48+
const dbProvider = os
49+
.$context<{ db?: Awaited<ReturnType<typeof connectDb>> }>()
50+
.middleware(async ({ context, next }) => {
51+
if (context.db) {
52+
return next({ context: { db: context.db } })
53+
}
54+
55+
const db = await connectDb()
56+
return next({ context: { db } })
57+
})
58+
// ---cut---
59+
const foo = os.use(dbProvider).handler(({ context }) => 'Hello World')
60+
61+
const bar = os.use(dbProvider).handler(({ context }) => call(foo, { context }))
62+
63+
const router = os
64+
.use(dbProvider)
65+
.use(({ next }) => {
66+
// Additional middleware logic
67+
return next()
68+
})
69+
.router({
70+
foo,
71+
bar,
72+
})
73+
```
74+
75+
Even when `dbProvider` is used multiple times, the middleware efficiently ensures that the database connection is established only once, preserving both correctness and performance.
76+
77+
## Conclusion
78+
79+
This recommended pattern leverages the context to prevent duplicate middleware execution, ensuring both efficiency and safety. We believe this approach is highly effective, and when writing middleware, you should keep this pattern in mind to avoid unnecessary overhead and potential performance issues.

0 commit comments

Comments
 (0)