Skip to content

Commit

Permalink
feat: allow stringify option
Browse files Browse the repository at this point in the history
Close #399
Close #382
  • Loading branch information
posva committed Jun 2, 2023
1 parent 1d04c7f commit afd0c5e
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 6 deletions.
15 changes: 15 additions & 0 deletions __tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,19 @@ describe('mande', () => {
await expect(api.get('/2')).resolves.toEqual({})
expect(fetchMock).toHaveFetched('/api/2')
})

it('calls the stringify with data on put and post', async () => {
const spy = jest.fn().mockReturnValue({ foo: 'bar' })
let api = mande('/api/', { stringify: spy })
fetchMock.mock('/api/', 204)
const data = {}
await expect(api.post(data)).resolves.toEqual(null)
expect(spy).toHaveBeenCalledTimes(1)
expect(spy).toHaveBeenCalledWith(data)
// second arg
fetchMock.mock('/api/a', 204)
await expect(api.put('/a', data)).resolves.toEqual(null)
expect(spy).toHaveBeenCalledTimes(2)
expect(spy).toHaveBeenNthCalledWith(2, data)
})
})
19 changes: 13 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ export interface Options<ResponseAs extends ResponseAsTypes = ResponseAsTypes>
* Headers sent alongside the request
*/
headers?: Record<string, string>

/**
* Optional function to stringify the body of the request for POST and PUT requests. Defaults to `JSON.stringify`.
*/
stringify?: (data: unknown) => string
}

export type ResponseAsTypes = 'json' | 'text' | 'response'
Expand Down Expand Up @@ -62,8 +67,7 @@ export interface MandeInstance {
/**
* Writable options.
*/
options: Required<Pick<OptionsRaw, 'headers'>> &
Pick<OptionsRaw, 'responseAs' | 'query'>
options: Required<Pick<OptionsRaw, 'headers'>> & Omit<OptionsRaw, 'headers'>

/**
* Sends a GET request to the given url.
Expand Down Expand Up @@ -217,12 +221,13 @@ function removeNullishValues(
* - 'Content-Type': 'application/json'
*/
export const defaults: Options &
Pick<Required<Options>, 'headers' | 'responseAs'> = {
Pick<Required<Options>, 'headers' | 'responseAs' | 'stringify'> = {
responseAs: 'json',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
stringify: JSON.stringify,
}

/**
Expand Down Expand Up @@ -270,7 +275,7 @@ export function mande(
data = dataOrOptions
}

let mergedOptions: Options = {
let mergedOptions = {
...defaults,
...instanceOptions,
method,
Expand All @@ -281,7 +286,7 @@ export function mande(
...instanceOptions.headers,
...localOptions.headers,
}),
}
} satisfies Options

let query = {
...defaults.query,
Expand All @@ -301,7 +306,9 @@ export function mande(

// only stringify body if it's a POST/PUT/PATCH, otherwise it could be the options object
// it's not used by GET/DELETE but it would also be wasteful
if (method[0] === 'P' && data) mergedOptions.body = JSON.stringify(data)
if (method[0] === 'P' && data) {
mergedOptions.body = mergedOptions.stringify(data)
}

// we check the localFetch here to account for global fetch polyfills and msw in tests
const localFetch = typeof fetch != 'undefined' ? fetch : fetchPolyfill!
Expand Down

0 comments on commit afd0c5e

Please sign in to comment.