npm package: @riribreizh/apifetch
Description: library wrapping fetch for easier usage
Author: Richard Gill
Latest version: 0.1.0
Deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

# apifetch

An API focused simplified **fetch**.

## Install

```
$ npm i @riribreizh/apifetch
```

## Basic usage

```js
import api from '@riribreizh/apifetch'

// with import we get a default instance of the API
// we can change a few properties (see options paragraph)
api.setBaseURL('http://myserver.api/v1')

// and make requests, JSON by default
let allUSers = await api.get('users')
let oneUser = await api.get('users', {
  email: 'username@domain.any'
})

// on POST requests the second argument is for additional parameters
// the third will make the json body
let newUser = await api.post('users', null, {
  email: 'username@domain.any',
  password: 'secret'
})

await api.delete('users', { id: newUser.id })
```

## Additional instances

But we can create new instances with specific options.
```js
import { createApiInstance } from '@riribreizh/apifetch'

const gitlabApi = createApiInstance({
    baseURL: 'https://gitlab.example.com/api/v4'
})

export gitlabApi
```

## Options

The **apifetch** object uses a set of options for each instance. You can set there any [fetch options](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters), plus a few ones that are specific to **apifetch**:

| Option | Default | Description |
|--------|---------|-------------|
| **baseURL** | `''` | URL prefix for all requests |
| **autoJson** | `true` | enables automatically converting data to JSON in requests and JSON to data in responses |
| **cached** | `true` | enables cache feature |
| **beforeRequest** | `[]` | see [Interceptors](#Interceptors) |
| **afterResponse** | `[]` | see [Interceptors](#Interceptors) |

## Methods

The first set of methods are to alter options after instance creation.

### setBaseURL(baseURL)

It's the URL prefix used for all requests. Hence, the *resource* parameter in request calls can be relative to this prefix, and really represent a resource.
```js
api.setBaseURL('https://gitlab.example.com/api/v4')
```

### setAutoJson(enable)

If set, any request with a *body*, and if no `Content-Type` header has been specified, will have the body converted to a JSON string.

In the other way, all responses with a `Content-Type` matching `/json/` will have their bodies converted to objects (or arrays)

If not enabled, the request requires a *body* as described by the `fetch` API and the response will be the bare *body* as returned by `fetch`.

### setCached(enable)

For all `GET` requests, a cache is maintained to avoid fetching the same data too quickly over the network. This cache is enabled by default, but can be disabled this way.

When data is cached for a specific URL, no network fetch is performed at all (unless a request interceptor is made to do it).
```js
api.setCached(false)
```

### setCacheLife(milliseconds)

Cached data is considered dirty after an amount of time (**1000** milliseconds by default). You can tweak the amount of time the cached data will remain valid for a specific URL.
```js
api.setCacheLife(500)
```
### updateAuthorization(token, type)

The `Authorization` header can be automatically set for all requests to manage... authorization. For this, you call this method with a *token* (or not to remove the authorization), and optionnaly a *type* which will be the header content prefix (defaults to `Bearer`).
```js
// enable authorization if mytoken is not null
api.updateAuthorization(myToken) // Authorization: Bearer {myToken}
// set authorization to API client ID
api.updateAuthorization(clientID, 'ClientID') // Authorization: ClientID {clientID}
// remove authorization header from all requests
api.updateAuthorization()
api.updateAuthorization(false) // same, more explicit
```

### Request methods

Unlike `fetch` you don't put query parameters in the URL directly (although you can if you want). The *resource* centric API style of **apifetch** separates the endpoint (base URL) from the *resource* denomination and its filtering through parameters.

The *params* parameter is an object containing query parameters (they all need to have a value, so `myurl?isNotPossible` is not available).

It's not possible either to mix query parameters in the *resource* **and** *params* parameters. **apifetch** is dumb and will try to insert two `?` in the URL.

```js
api.get(resource, params, additionalFetchOptions)
api.post(resource, params, body, additionalFetchOptions)
api.put(resource, params, body, additionalFetchOptions)
api.delete(resource, params, additionalFetchOptions)
api.patch(resource, params, body, additionalFetchOptions)
api.head(resource, params, additionalFetchOptions)
```

There is also a generic call where you can set your own method:
```js
api.request(method, resource, params, body, additionalFetchOptions)
```

## Interceptors

Interceptors permit to tweak requests and responses around `fetch` calls, through the **beforeRequest** and **afterResponse** options, which should be arrays of functions.

In **beforeRequest** each request function receives the final *url* and options passed to `fetch` and can either return:

* a `FetchParams` object containing modified *url* and *options* in its *input* and *init* properties respectively
* a `Response` object, in which case process is stopped and this response is returned to caller (hint: that's how mock can be implemented)
```js
import { FetchParams, createApiInstance } from 'apifetch'

const api = createApiInstance({
  // ...
  beforeRequest: [
    // dummy request interceptor
    async (url, options) => new FetchParams(url, options),
    // shortcuting interceptor sending a response
    async (url, options) => new Response('{}', {
      status: 200,
      statusText: 'I faked it!',
    })
  ]
})
```

Likewise, after `fetch` returns its response, this one can be altered with **afterResponse** interceptors with the request's *url* and *options*, plus a copy of the latest *response* (from `fetch` or previous interceptor).
```js
const api = createApiInstance({
  // ...
  afterResponse: [
    // dummy response interceptor
    async (url, options, response) => response
  ]
})
```

>**IMPORTANT**
>
> Interceptors must be inserted on the instance creation, or sent through requests options parameters. They can't be altered with methods.
>
> But you can manage arrays yourself and modify them after giving them by reference, to get the same result.

```js
const myRequestInterceptors = [
  async (url, options) => new FetchParams(url, options)
]

const api = createApiInstance({
  // ...
  beforeRequest: myRequestInterceptors
})

myRequestInterceptors.push(
  async (url, options) => new Response('{}', {
    status: 200,
    statusText: 'I faked it!',
  })
)
```