Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow for custom response parser with parseResponse #16

Merged
merged 12 commits into from
Oct 22, 2021
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,18 @@ const response = await $fetch.raw('/sushi')
// ...
```

## ✔️ Custom JSON parsing

By using `parse` option, `$fetch` determines how to parse data.

```js
// Disable JSON parsing
await $fetch('/movie?lang=en', { parse: false })

// Use JSON.parse to parse
await $fetch('/movie?lang=en', { parse: JSON.parse })
```

## 📦 Bundler Notes

- All targets are exported with Module and CommonJS format and named exports
Expand Down
17 changes: 15 additions & 2 deletions src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { joinURL, withQuery } from 'ufo'
import type { Fetch, RequestInfo, RequestInit, Response } from './types'
import { createFetchError } from './error'

type Parser = (text: string) => any
type GetParser = (parse: Parser | boolean | undefined) => Parser | undefined

export interface CreateFetchOptions { fetch: Fetch }

export type FetchRequest = RequestInfo
Expand All @@ -15,6 +18,7 @@ export interface FetchOptions extends Omit<RequestInit, 'body'> {
baseURL?: string
body?: RequestInit['body'] | Record<string, any>
params?: SearchParams
parse?: Parser | boolean
response?: boolean
}

Expand All @@ -25,6 +29,14 @@ export interface $Fetch {
raw<T = any>(request: FetchRequest, opts?: FetchOptions): Promise<FetchResponse<T>>
}

const getParser: GetParser = (parse) => {
if (!parse) {
return undefined
}

return parse === true ? destr : parse
}

export function setHeader (options: FetchOptions, _key: string, value: string) {
const key = _key.toLowerCase()
options.headers = options.headers || {}
Expand Down Expand Up @@ -59,15 +71,16 @@ export function createFetch ({ fetch }: CreateFetchOptions): $Fetch {
}
const response: FetchResponse<any> = await fetch(request, opts as RequestInit)
const text = await response.text()
response.data = destr(text)
const parse = getParser(opts?.parse)
response.data = parse ? parse(text) : text
if (!response.ok) {
throw createFetchError(request, response)
}
return response
}

const $fetch = function (request, opts) {
return raw(request, opts).then(r => r.data)
return raw(request, { parse: destr, ...opts }).then(r => r.data)
} as $Fetch

$fetch.raw = raw
Expand Down
14 changes: 12 additions & 2 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('ohmyfetch', () => {
let listener: Listener
const getURL = (url: string) => joinURL(listener.url, url)

it('setup', async () => {
beforeEach(async () => {
const app = createApp()
.use('/ok', () => 'ok')
.use('/params', req => (getQuery(req.url || '')))
Expand All @@ -17,14 +17,24 @@ describe('ohmyfetch', () => {
listener = await listen(app)
})

afterAll(async () => {
afterEach(async () => {
await listener.close()
})

it('ok', async () => {
expect(await $fetch(getURL('ok'))).toBe('ok')
})

it('custom parse', async () => {
const parser = jest.fn().mockReturnValue('asdf')
await $fetch(getURL('ok'), { parse: parser })
expect(parser).toHaveBeenCalledTimes(1)
})

it('custom parse false', async () => {
expect(await $fetch(getURL('ok'), { parse: false })).toBe('ok')
})

it('baseURL', async () => {
expect(await $fetch('/x?foo=123', { baseURL: getURL('url') })).toBe('/x?foo=123')
})
Expand Down