Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export abstract class APIClient {
protected defaultHeaders(opts: FinalRequestOptions): Headers {
return {
Accept: 'application/json',
...(['head', 'get'].includes(opts.method) ? {} : { 'Content-Type': 'application/json' }),
...(['head', 'get', 'delete'].includes(opts.method) ? {} : { 'Content-Type': 'application/json' }),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve JSON content type for DELETE requests with bodies

When a caller uses the supported generic API for a JSON-bearing request such as client.delete('/some/path', { body: { ... } }), buildRequest still serializes and sends that body, but this method-only condition now omits Content-Type: application/json. Fetch implementations may consequently label the serialized string as text/plain or leave it untyped, causing DELETE endpoints that parse JSON to reject or misinterpret the request. Omit the header only when the DELETE request has no body rather than for every DELETE.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed — DELETE with a body keeps Content-Type: application/json when a JSON body is present (method alone no longer strips it).

'User-Agent': this.getUserAgent(),
...getPlatformHeaders(),
...this.authHeaders(opts),
Expand Down
18 changes: 18 additions & 0 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,24 @@ describe('instantiate client', () => {
expect(capturedRequest?.method).toEqual('PATCH');
});

test('does not set Content-Type on DELETE (#180)', async () => {
const client = new Browserbase({
baseURL: 'http://localhost:5000/',
apiKey: 'My API Key',
});
const { req } = await client.buildRequest({ path: '/v1/contexts/id', method: 'delete' });
expect(req.headers as Headers).not.toHaveProperty('content-type');
});

test('still sets Content-Type on POST', async () => {
const client = new Browserbase({
baseURL: 'http://localhost:5000/',
apiKey: 'My API Key',
});
const { req } = await client.buildRequest({ path: '/foo', method: 'post', body: { a: 1 } });
expect((req.headers as Headers)['content-type']).toEqual('application/json');
});

describe('baseUrl', () => {
test('trailing slash', () => {
const client = new Browserbase({ baseURL: 'http://localhost:5000/custom/path/', apiKey: 'My API Key' });
Expand Down