Skip to content

fix: support edge/serverless runtimes via axios adapter fallback (#31) - #107

Open
CedricConday wants to merge 1 commit into
mailerlite:mainfrom
CedricConday:fix/edge-runtime-fetch-adapter
Open

fix: support edge/serverless runtimes via axios adapter fallback (#31)#107
CedricConday wants to merge 1 commit into
mailerlite:mainfrom
CedricConday:fix/edge-runtime-fetch-adapter

Conversation

@CedricConday

Copy link
Copy Markdown

Problem

The SDK throws in runtimes that don't ship Node's http module — Vercel Edge Functions, Cloudflare Workers, Next.js edge routes, Deno — because axios can't find a usable adapter (reported in #31):

AxiosError: There is no suitable adapter to dispatch the request since :
- adapter xhr is not supported by the environment
- adapter http is not available in the build

Fix

axios ≥ 1.7 accepts an ordered list of adapters and selects the first one supported by the current runtime. All requests already funnel through a single request() helper (src/utils/fetch.ts), so one change covers the whole SDK:

adapter: ["http", "xhr", "fetch"]
  • Node → keeps using http (no behaviour change; all recorded-tape tests stay green)
  • Browsers → keep using xhr
  • Edge / serverless (no http/xhr) → transparently fall back to the universal fetch adapter

No new dependencies, no breaking changes, no major version needed. axios@^1.15.0 (already the declared dependency) ships the fetch adapter.

Tests

  • Added src/utils/fetch.test.ts — a self-contained unit test (mocks axios, no network/API key) asserting the adapter fallback order.
  • Full existing suite still passes (40 tape-replayed tests green; Node continues to select http).

Docs

Added a short Edge & serverless runtimes note to the README.

Fixes #31

🤖 Generated with Claude Code

https://claude.ai/code/session_01DbUHs855FyBt2J7cG2Qmhh

…lerlite#31)

The SDK hard-failed in runtimes that don't ship Node's `http` module
(Vercel Edge, Cloudflare Workers, Next.js edge routes, Deno) with
`AxiosError: There is no suitable adapter to dispatch the request`.

axios >= 1.7 can be given an ordered list of adapters and picks the
first one supported by the current runtime. Passing
`["http", "xhr", "fetch"]` keeps Node on `http` and browsers on `xhr`
(no behaviour change), while edge/serverless runtimes that ship neither
transparently fall back to the universal `fetch` adapter.

Adds a self-contained unit test (mocks axios, no network) and documents
edge support in the README.

Fixes mailerlite#31

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbUHs855FyBt2J7cG2Qmhh

@Mantas97 Mantas97 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CedricConday Clever solution for the problem 👍 Just one detail that needs to be addressed

Comment thread src/utils/fetch.ts
"accept-encoding": "null" // needed for axios
},
data: body && JSON.stringify(body)
data: body && JSON.stringify(body),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
data: body && JSON.stringify(body),
// Must be `undefined`, not `null`, when there is no body: workerd
// (Cloudflare Workers) rejects a GET/HEAD Request that carries any
// body property, even a null one. Node's http adapter tolerates it.
data: body ? JSON.stringify(body) : undefined,

Comment thread src/utils/fetch.test.ts
// edge/serverless runtimes fall back to `fetch`. See issue #31.
expect(passedConfig.adapter).toEqual(["http", "xhr", "fetch"]);
});
});

@Mantas97 Mantas97 Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth adding one more test along with the fix:

describe("request body handling", () => {
    beforeEach(() => {
        axiosMock.mockClear();
    });

    // Regression: `data: body && JSON.stringify(body)` yielded `null` on
    // bodyless calls. Node's http adapter ignores that, but workerd throws
    // "Request with a GET or HEAD method cannot have a body", breaking every
    // read call on Cloudflare Workers once the fetch adapter is in play.
    it("omits `data` entirely when there is no body", async () => {
        await request("/api/subscribers", { method: "GET" }, config);

        const passedConfig = axiosMock.mock.calls[0][0] as { data: unknown };
        expect(passedConfig.data).toBeUndefined();
        expect(passedConfig.data).not.toBeNull();
    });

    it("still serializes a body when one is given", async () => {
        await request(
            "/api/subscribers",
            { method: "POST", body: { email: "test@example.com" } },
            config
        );

        const passedConfig = axiosMock.mock.calls[0][0] as { data: unknown };
        expect(passedConfig.data).toBe('{"email":"test@example.com"}');
    });
})

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.

Library is not compatible with CloudFlare Workers / Vercel Edge functions

2 participants