diff --git a/.changeset/bumpy-parrots-lie.md b/.changeset/bumpy-parrots-lie.md new file mode 100644 index 000000000..dcff2da4a --- /dev/null +++ b/.changeset/bumpy-parrots-lie.md @@ -0,0 +1,5 @@ +--- +"openapi-fetch": patch +--- + +Improve header handling diff --git a/package.json b/package.json index 66d30f924..0f9423af5 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "size-limit": "^11.2.0", "turbo": "^2.5.2", "typescript": "^5.8.3", - "vitest": "^3.0.0" + "vitest": "^3.1.3" }, "size-limit": [ { diff --git a/packages/openapi-fetch/src/index.js b/packages/openapi-fetch/src/index.js index 9db46952c..4b226c870 100644 --- a/packages/openapi-fetch/src/index.js +++ b/packages/openapi-fetch/src/index.js @@ -73,24 +73,38 @@ export default function createClient(clientOptions) { }); } - const serializedBody = body === undefined ? undefined : bodySerializer(body, headers); - - const defaultHeaders = + const serializedBody = + body === undefined + ? undefined + : bodySerializer( + body, + // Note: we declare mergeHeaders() both here and below because it’s a bit of a chicken-or-egg situation: + // bodySerializer() needs all headers so we aren’t dropping ones set by the user, however, + // the result of this ALSO sets the lowest-priority content-type header. So we re-merge below, + // setting the content-type at the very beginning to be overwritten. + // Lastly, based on the way headers work, it’s not a simple “present-or-not” check becauase null intentionally un-sets headers. + mergeHeaders(baseHeaders, headers, params.header), + ); + const finalHeaders = mergeHeaders( // with no body, we should not to set Content-Type serializedBody === undefined || - // if serialized body is FormData; browser will correctly set Content-Type & boundary expression - serializedBody instanceof FormData + // if serialized body is FormData; browser will correctly set Content-Type & boundary expression + serializedBody instanceof FormData ? {} : { "Content-Type": "application/json", - }; + }, + baseHeaders, + headers, + params.header, + ); const requestInit = { redirect: "follow", ...baseOptions, ...init, body: serializedBody, - headers: mergeHeaders(defaultHeaders, baseHeaders, headers, params.header), + headers: finalHeaders, }; let id; diff --git a/packages/openapi-metadata/package.json b/packages/openapi-metadata/package.json index 93511880e..a2c917c9b 100644 --- a/packages/openapi-metadata/package.json +++ b/packages/openapi-metadata/package.json @@ -68,7 +68,7 @@ }, "devDependencies": { "@types/node": "^22.15.3", - "@vitest/coverage-v8": "^3.0.0", + "@vitest/coverage-v8": "^3.1.3", "reflect-metadata": "^0.2.2", "typescript": "^5.8.3", "unbuild": "^3.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1dfb138b8..463b041a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,7 +42,7 @@ importers: specifier: ^5.8.3 version: 5.8.3 vitest: - specifier: ^3.0.0 + specifier: ^3.1.3 version: 3.1.3(@types/debug@4.1.12)(@types/node@22.15.17)(jiti@2.4.2)(jsdom@20.0.3)(msw@2.8.2(@types/node@22.15.17)(typescript@5.8.3))(yaml@2.7.1) docs: @@ -221,7 +221,7 @@ importers: specifier: ^22.15.3 version: 22.15.17 '@vitest/coverage-v8': - specifier: ^3.0.0 + specifier: ^3.1.3 version: 3.1.3(vitest@3.1.3(@types/debug@4.1.12)(@types/node@22.15.17)(jiti@2.4.2)(jsdom@20.0.3)(msw@2.8.2(@types/node@22.15.17)(typescript@5.8.3))(yaml@2.7.1)) reflect-metadata: specifier: ^0.2.2