swagger-typescript-api icon indicating copy to clipboard operation
swagger-typescript-api copied to clipboard

Fix: Response object mutation fails in ESM environments with node-fetch v3

Open omarmciver opened this issue 3 months ago • 0 comments

Problem

The generated Fetch client attempts to directly mutate the Response object by adding data and error properties. This fails in ESM environments using node-fetch v3 because Response objects are read-only.

Error

TypeError: Cannot set property data of #<Body> which has only a getter
    at /node_modules/.pnpm/@[email protected]/node_modules/@oars/v1.ts:1237:13

Environment

  • Node.js with ESM modules ("type": "module" in package.json)
  • node-fetch v3.x (ESM-only version)
  • swagger-typescript-api v13.0.23 (also confirmed in v13.2.13)

Root Cause

In templates/base/http-clients/fetch-http-client.ejs (lines 187-189), the code attempts to directly mutate the Response object:

const r = response as HttpResponse<T, E>;
r.data = (null as unknown) as T;
r.error = (null as unknown) as E;

This works in CommonJS environments but fails in ESM with node-fetch v3 where Response objects are truly read-only and cannot have new properties added.

Impact

Anyone migrating to ESM modules or using node-fetch v3 cannot use the generated Fetch client without workarounds.

Current Workaround

Users must wrap fetch with a Proxy to make Response properties writable:

const wrappedFetch = async (...args) => {
  const response = await fetch(...args);
  return new Proxy(response, {
    set(target, prop, value) {
      if (prop === 'data' || prop === 'error') {
        target[prop] = value;
        return true;
      }
      return Reflect.set(target, prop, value);
    },
    get(target, prop) {
      if (prop === 'data' || prop === 'error') {
        return target[prop];
      }
      const value = target[prop];
      if (typeof value === 'function') {
        return value.bind(target);
      }
      return value;
    }
  });
};

Proposed Solution

Create a wrapper object instead of mutating the Response directly. This maintains backward compatibility while supporting modern ESM environments.

I'll be submitting a PR with a fix shortly.

omarmciver avatar Sep 23 '25 12:09 omarmciver