with-middleware.ts
Overview
The with-middleware.ts file provides a utility function to enhance a base SWR hook by applying middleware. This function, withMiddleware, is a higher-order hook wrapper that enables the composition of middleware functions on top of the core useSWR hook. Middleware in this context are functions that extend or customize the behavior of SWR hooks, such as adding logging, caching strategies, or integration with devtools.
By using withMiddleware, developers can create new hooks that incorporate additional middleware behavior transparently, without modifying the original hook implementation. This promotes modularity, composability, and separation of concerns in the data fetching lifecycle.
Detailed Explanation
Function: withMiddleware
export const withMiddleware = (
useSWR: SWRHook,
middleware: Middleware
): SWRHook => {
return <Data = any, Error = any>(
...args:
| [Key]
| [Key, Fetcher<Data> | null]
| [Key, SWRConfiguration | undefined]
| [Key, Fetcher<Data> | null, SWRConfiguration | undefined]
) => {
const [key, fn, config] = normalize(args)
const uses = (config.use || []).concat(middleware)
return useSWR<Data, Error>(key, fn, { ...config, use: uses })
}
}
Purpose
withMiddleware creates a new SWR hook by wrapping an existing useSWR hook and injecting a middleware function into its configuration. The returned hook behaves identically to the original but with the added middleware applied.
Parameters
Parameter | Type | Description |
|---|---|---|
|
| The original SWR hook to be enhanced. |
|
| The middleware function to apply. |
Returns
Return Type | Description |
|---|---|
| A new SWR hook that applies the given middleware on top of the original hook. |
Generics
<Data = any>: The type of the data returned by the fetcher.<Error = any>: The type of the error that might be returned.
Function Signature of Returned Hook
The returned hook supports multiple calling signatures, matching the flexibility of the base useSWR hook:
(key: Key) => SWRResponse<Data, Error>(key: Key, fetcher: Fetcher<Data> | null) => SWRResponse<Data, Error>(key: Key, config?: SWRConfiguration) => SWRResponse<Data, Error>(key: Key, fetcher: Fetcher<Data> | null, config?: SWRConfiguration) => SWRResponse<Data, Error>
Implementation Details
Argument Normalization:
The hook uses the
normalizeutility function imported from'./normalize-args'to parse the variable arguments into three normalized entities:key: The cache key or resource identifier.fn: The fetcher function ornull.config: The SWR configuration object.
Middleware Chaining:
It reads any existing middleware in
config.use(an array of middleware functions). The newmiddlewarepassed towithMiddlewareis concatenated at the end of this array, preserving existing middleware and enforcing middleware layering order.Hook Invocation:
The original
useSWRhook is invoked with the normalizedkey,fn, and an augmented configuration that includes the extended middleware array.
Usage Example
import useSWR from 'swr'
import { withMiddleware } from './with-middleware'
import { someMiddleware } from './middleware/someMiddleware'
// Create a new hook enhanced with `someMiddleware`
const useSWRWithMiddleware = withMiddleware(useSWR, someMiddleware)
// Use the enhanced hook in a React component
function Profile() {
const { data, error } = useSWRWithMiddleware('/api/user')
if (error) return <div>Failed to load</div>
if (!data) return <div>Loading...</div>
return <div>Hello {data.name}</div>
}
Interaction with Other Parts of the System
Core SWR Hook (
useSWR):withMiddlewarewraps the core hook, extending its behavior without modifying its internal implementation.Normalization Utility (
normalize-args): Ensures consistent argument parsing to support multiple call signatures.Middleware Functions: Middleware passed to
withMiddlewarecan be any function conforming to theMiddlewaretype, allowing extensible behavior such as devtools integration, caching strategies, or preloading.Middleware Presets: Often used in combination with middleware presets (e.g., devtools, preload), allowing developers to compose multiple middleware layers seamlessly.
Configuration Object (
SWRConfiguration): Middleware are passed via theusearray in the configuration, whichwithMiddlewaremanages.
This design enables flexible and declarative middleware composition in the SWR ecosystem.
Important Implementation Notes
Middleware Ordering: Middleware are executed in the order they appear in the
usearray.withMiddlewareappends the new middleware to the end, ensuring earlier middleware run before it.Type Safety: The function supports generics for
DataandErrortypes, preserving type information through the middleware chain.Flexible Arguments: The use of
normalizeallows the composed hook to accept multiple calling variants, enhancing developer ergonomics.Pure Wrapper:
withMiddlewaredoes not internally change the behavior of the hook; it only extends the middleware configuration to layer behavior.
Mermaid Diagram: Structure of with-middleware.ts
classDiagram
class withMiddleware {
+withMiddleware(useSWR: SWRHook, middleware: Middleware): SWRHook
}
class SWRHook {
<<function>>
+<Data, Error>(...args): SWRResponse<Data, Error>
}
class Middleware {
<<function>>
+middleware(hook: SWRHook): SWRHook
}
withMiddleware --> SWRHook : wraps
withMiddleware --> Middleware : appends to config.use
Summary
The with-middleware.ts file defines a single but crucial utility function withMiddleware that enables the composition of middleware on top of the core SWR hook. By normalizing the hook arguments and managing the middleware array in the configuration, it returns a new hook that applies the given middleware transparently. This pattern supports the extensible middleware architecture of the project, allowing modular features to be layered without complicating the core hook logic.
This function serves as the foundational building block for middleware composition in the SWR ecosystem, facilitating maintainability, customization, and scalability of data fetching behaviors.
References
normalize-args.ts— Utility to normalize hook arguments.Middleware Architecture Documentation — Conceptual overview of middleware patterns.
Core SWR Hook — The base hook enhanced by middleware.
Middleware Presets — Bundled middleware arrays for common use cases.