Skip to content

feat: add support for custom fetch overrides via FormioProvider and F…#642

Open
AyoubSayah wants to merge 1 commit into
formio:mainfrom
AyoubSayah:feature/add_custom_fetch
Open

feat: add support for custom fetch overrides via FormioProvider and F…#642
AyoubSayah wants to merge 1 commit into
formio:mainfrom
AyoubSayah:feature/add_custom_fetch

Conversation

@AyoubSayah

Copy link
Copy Markdown
Contributor

This PR introduces a React-idiomatic way to provide a custom fetch function to Form.io network requests. It adds a customFetch prop to both the

component and the , eliminating the need for consumers to manually mutate the global Formio.fetch prototype as a side-effect.

🕵️‍♂️ Why are we making this change?
Currently, to customize the fetch function (e.g., for adding authorization headers, integrating React Query, or custom error handling), consumers must mutate the global module:

tsx
import { Formio } from 'formiojs';
Formio.fetch = myCustomFetchFunction; // Global side-effect!
This is problematic in React applications because:

Global Mutation: It affects every Form.io instance across the entire application.
Not React-Idiomatic: React components should be declarative and configurable via props, not by mutating globals before rendering.
Hard to Test: Testing different forms with different fetch strategies in the same suite causes global state to leak between tests.
🛠️ How is it implemented?
FormioCustomFetch Type: Exported a new type representing the native fetch API signature.
Integration: customFetch can be passed to the provider to act as the default fallback for all nested forms via React Context.

Component: Accepts a customFetch prop. Because @formio/core currently hardcodes network requests to the static Formio.fetch property, the component safely manages this global state internally. It intercepts the form instantiation, safely swaps Formio.fetch to the provided customFetch during initialization, and cleans up after itself on unmount. 🏗️ Architecture Note Because the underlying @formio/core SDK does not currently support instance.fetch (it hardcodes the static Formio.fetch in Formio.request), the React wrapper manages this state via a useEffect cleanup pattern. If/when @formio/core supports true per-instance fetch properties, the internal logic of this React component can be updated with zero breaking changes to the consumer's public API.

📋 Testing & Verification
✅ Added customFetch.test.tsx testing the prop, the context fallback, override precedence, and unmount restoration.
✅ All 8 tests pass locally.
✅ Updated README.md with full usage examples for single-form and provider-level configurations.
📖 Code Example
tsx
import { Form } from '@formio/react';
// Easily scope fetch behavior to a specific form declaratively
const MyForm = () => (

{ const response = await fetch(url, { ...init, headers: { ...init?.headers, Authorization: `Bearer ${getToken()}`, }, }); return response; }} /> );

@AyoubSayah

Copy link
Copy Markdown
Contributor Author

Just to provide some real-world context on why this is so valuable:

In one of our active projects, I manually overrode the fetch instance to pipe Form.io's internal network requests through React Query. It worked beautifully and allowed us to leverage all of our existing caching mechanisms.

However, doing it via global mutation was messy and caused state to leak across our React component tree. I built this PR so that the rest of the community can cleanly and declaratively integrate tools like React Query directly via props without having to fight the global prototype!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant