Skip to content

Commit

Permalink
Update zlFetch to create instance
Browse files Browse the repository at this point in the history
  • Loading branch information
zellwk committed Nov 5, 2022
1 parent ffa76b0 commit 87e77bd
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 61 deletions.
52 changes: 39 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ You can add `query` or `queries` as an option and zlFetch will create a query st
zlFetch('some-url', {
queries: {
param1: 'value1',
param2: 'to encode'
}
param2: 'to encode',
},
})

// The above request can be written in Fetch like this:
Expand All @@ -119,14 +119,14 @@ It will also help you `JSON.stringify` your body so you don't have to do it your

```js
zlFetch.post('some-url', {
body: { message: 'Good game' }
body: { message: 'Good game' },
})

// The request above can be written in Fetch like this:
fetch('some-url', {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: 'Good game' })
body: JSON.stringify({ message: 'Good game' }),
})
```

Expand All @@ -137,15 +137,15 @@ If you set `Content-Type` to `application/x-www-form-urlencoded`, zlFetch will a
```js
zlFetch.post('some-url', {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
'Content-Type': 'application/x-www-form-urlencoded',
},
body: { message: 'Good game' }
body: { message: 'Good game' },
})

// The request above can be written in Fetch like this:
fetch('some-url', {
method: 'post',
body: 'message=Good+game'
body: 'message=Good+game',
})
```

Expand All @@ -160,7 +160,7 @@ zlFetch('some-url', { auth: 'token12345' })

// The above request can be written in Fetch like this:
fetch('some-url', {
headers: { Authorization: `Bearer token12345` }
headers: { Authorization: `Bearer token12345` },
})
```

Expand Down Expand Up @@ -193,8 +193,9 @@ zlFetch directs all 400 and 500 errors to the `catch` method. Errors contain the
This makes is zlFetch super easy to use with promises.

```js
zlFetch('some-url')
.catch(error => { /* Handle error */})
zlFetch('some-url').catch(error => {
/* Handle error */
})

// The above request can be written in Fetch like this:
fetch('some-url')
Expand All @@ -203,13 +204,15 @@ fetch('some-url')
Promise.reject(response.json)
}
})
.catch(error => { /* Handle error */})
.catch(error => {
/* Handle error */
})
```

zlFetch also gives you the option to pass all errors into an `errors` object instead of handling them in `catch`. This option is very much preferred when you don't your errors to be passed into a catch method. (Very useful when used in servers).

```js
const {response, error} = await zlFetch('some-url')
const { response, error } = await zlFetch('some-url')
```

`zlFetch` changes the response and error objects. In zlFetch, `response` and `error` objects both include these five properties:
Expand Down Expand Up @@ -241,7 +244,30 @@ If you want to handle a response not supported by zlFetch, you can pass `customR

```js
const response = await zlFetch('url', {
customResponseParser: true
customResponseParser: true,
})
const data = await response.arrayBuffer()
```

## Creating a zlFetch instance

This feature is super useful if you are going to send requests with the similar options url or options.

```js
import { createZLFetch } from 'zl-fetch'

// Creating the instance
const api = zlFetch(baseUrl, options)

// Using the created instance
const response = api.post('/resource', {
body: {
message: 'Hello',
},
})
```

A few notes here:

- `baseURL` will be prepended to the `url` for all requests made with the instance.
- `options` will be merged with the options passed into request. The request options will override the instance options.
54 changes: 44 additions & 10 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { handleError, handleResponse } from './handleResponse.js'

/* globals fetch */
import createRequestOptions from './createRequestOptions.js'
import { handleResponse, handleError } from './handleResponse.js'

/**
* Main zlFetch Function
Expand All @@ -14,24 +15,57 @@ import { handleResponse, handleError } from './handleResponse.js'
* @param {string} options.returnError - Returns the error instead of rejecting it
* @param {string} options.customResponseParser - Use a custome response parser
*/
export default function zlFetch (url, options) {
export default function zlFetch(url, options) {
return fetchInstance({ url, ...options })
}

// Shorthand methods
// Create Shorthand methods
const methods = ['get', 'post', 'put', 'patch', 'delete']

for (const method of methods) {
zlFetch[method] = function (url, options) {
options = Object.assign({ method }, options)
return zlFetch(url, options)
return fetchInstance({ url, method, ...options })
}
}

// Creates an instance of zlFetch to be used later
export function createZlFetch(baseURL, options) {
const fn = function (url, newOptions) {
url = makeURL(baseURL, url)
return fetchInstance({ url, ...options, ...newOptions })
}

// Create Shorthand methods
const methods = ['get', 'post', 'put', 'patch', 'delete']

for (const method of methods) {
fn[method] = function (url, newOptions) {
url = makeURL(baseURL, url)
return fetchInstance({ url, method, ...options, ...newOptions })
}
}

return fn
}

// Joins the baseURL and endpoint.
// Uses a simple string concatenation instead of path.join
function makeURL(baseURL, url) {
if (baseURL.endsWith('/') && url.startsWith('/')) {
url = url.slice(1)
}

if (!baseURL.endsWith('/') && !url.startsWith('/')) {
url = '/' + url
}

return baseURL + url
}

// ========================
// Internal Functions
// ========================
async function fetchInstance (options) {
async function fetchInstance(options) {
const fetch = await getFetch()
const requestOptions = createRequestOptions({ ...options, fetch })

Expand All @@ -53,22 +87,22 @@ async function fetchInstance (options) {
}

// Normalizes between Browser and Node Fetch
export async function getFetch () {
export async function getFetch() {
if (typeof fetch === 'undefined') {
const f = await import('node-fetch')
return {
fetch: f.default,
Headers: f.Headers
Headers: f.Headers,
}
} else {
return {
fetch: window.fetch.bind(window),
Headers: window.Headers
Headers: window.Headers,
}
}
}

function debugHeaders (requestOptions) {
function debugHeaders(requestOptions) {
const clone = Object.assign({}, requestOptions)
const headers = {}
for (const [header, value] of clone.headers) {
Expand Down
3 changes: 2 additions & 1 deletion test/browser.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @vitest-environment jsdom
import { beforeEach, afterEach } from 'vitest'
import { afterEach, beforeEach } from 'vitest'
import { setup, teardown } from './helpers/setup.js'

import integrationTests from './helpers/integration-tests.js'

beforeEach(setup)
Expand Down

0 comments on commit 87e77bd

Please sign in to comment.