Recipes
One /me per page view on the server
Use this when you render pages on a server, and several of a page’s loaders, running in parallel, each need the current user. There is no store to hold the user between them, so each loader asks for it.
Use one client for the whole server, share: true on the endpoint, and a copy of the client for each page view that sends the user’s cookie (withHeaders()). User and IncomingRequest stand for your types; cookie stands for however you pass the user’s identity.
import { createApi, defineRequest, withHeaders } from 'liaise'
const me = defineRequest<User>()({ method: 'GET', path: '/me', share: true })
// One client for the whole server. Sharing compares what is actually sent,
// so one user's call never joins another's.
const api = createApi({ baseUrl: 'https://users.internal', requests: { me } })
async function renderPage(req: IncomingRequest) {
// A copy of the client that sends this user's cookie on every call.
const user = withHeaders(api, { cookie: req.headers.cookie ?? '' })
const [header, cart] = await Promise.all([
user.me().then(r => r.data?.name), // header loader
user.me().then(r => r.data?.cartId), // cart loader
])
return { header, cart }
}
Why it works
Both loaders for one page send the same cookie, so their requests are identical, and share sends one. A page for another user sends a different cookie, so its call never joins. Two pages rendering at once for two users make two requests, and each page gets its own user.
- Sharing compares the request as it is sent, after all your middleware, headers included. The cookie is a header, so one user’s call never joins another’s.
- Only calls in flight at the same moment share. A loader that starts after the request has settled sends a new one.
- The comparison sees only what liaise sends: the method, URL, headers, body and
fetchOptions. If something outside liaise adds the user’s identity, such as a patched globalfetch, afetchyou gave the client that adds it from request context, or instrumentation that reads request context, liaise can’t see it, andshareis unsafe in that setup (On a server).
Inside React Server Components, React’s cache() gives one /me per page view too. React clears it for each server request.
Next: Retry a flaky backend within one deadline retries the failures worth a second try, and still answers on time.