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

useSWR

SWRHook

The original SWR hook to be enhanced.

middleware

Middleware

The middleware function to apply.


Returns

Return Type

Description

SWRHook

A new SWR hook that applies the given middleware on top of the original hook.


Generics


Function Signature of Returned Hook

The returned hook supports multiple calling signatures, matching the flexibility of the base useSWR hook:


Implementation Details

  1. Argument Normalization:

    The hook uses the normalize utility 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 or null.

    • config: The SWR configuration object.

  2. Middleware Chaining:

    It reads any existing middleware in config.use (an array of middleware functions). The new middleware passed to withMiddleware is concatenated at the end of this array, preserving existing middleware and enforcing middleware layering order.

  3. Hook Invocation:

    The original useSWR hook is invoked with the normalized key, 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

This design enables flexible and declarative middleware composition in the SWR ecosystem.


Important Implementation Notes


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