# fetch-decorators

> A set of ES7 composable decorators around the fetch api

Latest version **0.0.7** (published 2016-02-16) · MIT license · 0 weekly downloads

## Install

```sh
npm install fetch-decorators
pnpm add fetch-decorators
yarn add fetch-decorators
bun add fetch-decorators
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.0.7 |
| Published | 2016-02-16 |
| First published | 2015-10-28 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 13 |
| Author | Arnaud Rinquin |
| Maintainers | arnaudrinquin |
| Keywords | fetch, decorators, es7, es2016 |

## Links

- npm: https://www.npmjs.com/package/fetch-decorators
- Repository: https://github.com/ArnaudRinquin/fetch-decorators
- Homepage: https://github.com/ArnaudRinquin/fetch-decorators#readme
- Issues: https://github.com/ArnaudRinquin/fetch-decorators/issues
- npm.io page: https://npm.io/package/fetch-decorators

## Alternatives

- [gamedig](https://npm.io/package/gamedig.md) — 29.3K weekly downloads
- [join-monster](https://npm.io/package/join-monster.md) — 12.8K weekly downloads
- [masked](https://npm.io/package/masked.md) — 5.5K weekly downloads
- [@comunica/actor-query-process-explain-logical](https://npm.io/package/@comunica/actor-query-process-explain-logical.md) — 4.7K weekly downloads
- [@veracity/vui](https://npm.io/package/@veracity/vui.md) — 4.6K weekly downloads

## Recent versions

- 0.0.7 (latest) — 2016-02-16
- 0.0.6 — 2015-10-28
- 0.0.5 — 2015-10-28
- 0.0.4 — 2015-10-28
- 0.0.3 — 2015-10-28
- 0.0.2 — 2015-10-28
- 0.0.1 — 2015-10-28
- 0.0.0 — 2015-10-28

## README

# fetch-decorators

[![npm package](http://img.shields.io/npm/v/fetch-decorators.svg)](https://www.npmjs.com/package/fetch-decorators)
[![Build Status](https://img.shields.io/travis/ArnaudRinquin/fetch-decorators.svg)](https://travis-ci.org/ArnaudRinquin/fetch-decorators)
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
[![Code Climate](https://img.shields.io/codeclimate/github/ArnaudRinquin/fetch-decorators.svg)](https://codeclimate.com/github/ArnaudRinquin/fetch-decorators)
[![Test Coverage](https://img.shields.io/codeclimate/coverage/github/ArnaudRinquin/fetch-decorators.svg)](https://codeclimate.com/github/ArnaudRinquin/fetch-decorators/coverage)
[![npm package](http://img.shields.io/npm/l/fetch-decorators.svg)](https://www.npmjs.com/package/fetch-decorators)

A set of [composable](#composition) [ES7 decorators](https://github.com/wycats/javascript-decorators) around the `fetch` api

Automate things request and response body parsing so you don't have to.

No dependency (oh, except a [fetch polyfill](https://github.com/github/fetch) maybe)

## Usage TL;DR:

```sh
npm i -S fetch-decorators
```

```js
class Messages {
  @extractJson
  @bodify
  @fetchify({method: 'POST'})
  post(userId) {
    return `/users/${userId}/messages`;
  }
}

const messages = new Messages();

messages.post('ArnaudRinquin')({
  content: 'Hello World',
  public: true,
  draft: false,
}).then(({response, data}) => {
  // response === the original fetch response
  // data === the JSON object returned by the server
});

```

## Decorators

* [`@fetchify`](#fetchifyoptionsobject): decorates a function returning a url to a `fetch` call with your options.
* [`@bodify`](#bodify): prepare passed data (and extra options) into fetch-ready body options.
* [`@extractJson`, `@extractText,` `@extractBlob`](#extractjson-extracttext-extractblob): decorates a function returning a `Response` to extract its result as json, text or blob.
* [`@extractAuto`](#extractauto): decorates a function returning a `Response` to extract its result automatically based on response `Content-Type` header.

These decorators have been designed to be [composable](#composition), give it a try!

### @fetchify(options:?object)

This helper wraps the original function into a fetch call so it may just return a string, and then be called with optional data, headers, options.


`(originalArgs) => url:string`

becomes:

`(originalArgs) => (options:?object) => fetchResponse:promise`

```js
import { fetchify } from 'fetch-decorators';

class Users {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
  }

  @fetchify()
  get(userId) {
    return `${this.baseUrl}/users/${userId}`;
  }

  @fetchify({
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
    }
  })
  create() {
    return `${this.baseUrl}/users`;
  }
}

const userApi = new UserApi('/api');

userApi.createUser()({
  body: JSON.stringify({
    firstName: 'Walter',
    lastName: 'White',
  }
})).then(function(response){
  // Regular `fetch` response
);

userApi.getUser('fakeUserId123')().then(function(response){
  // Regular `fetch` response
});
```

### @bodify

Takes body data and options and calls the decorated function with a proper fetch `options` object where `options.body` is passed data as a string.

`(options) => orignalResult`

becomes:

`(originalArgs) => (data:object, extraOptions:?object) => orignalResult(options)`

```js
import { bodify } from 'fetch-decorators';

class Messages {
  @bodify
  create(userId) {
    return function(options) {
      return fetch(`/api/users/${userId}/messages`, options);
    };
  }
}

const messages = new Messages();
const messages = {
  content: 'Hello',
  draft: false,
};
const options = { method: 'POST' };

users.create('fakeUserId')(message, options).then(function(response){
  // response === the original fetch response
});
```

### @extractJson, @extractText, @extractBlob

These decorators wrap functions returning a fetch promise with the matching Response extraction function.

`(originalArgs) => fetchResponse:promise`

becomes:

`(originalArgs) => (options:?object) => extractionResult:promise`

where the `extractionResult` promise resolves with : `{response:Response, data:any}`

```js
import { extractJson } from 'fetch-decorators';

class Users {
  @extractJson
  get(userId) {
    return (options) => fetch(`/api/users/${userId}`, options);
  }
}

const users = new Users();

users.get('userId123')().then(function({response, data}){
  // response === the original fetch response
  // data === the extracted data, here a `user` JSON object
});

```

### @extractAuto

This extractor has the same signature and behaviour as other extractors but will use the Reponse `Content-Type` header to determine the right Response method to use for data extraction.

Content types are matched this way:

```
'application/json': 'json'
'text/plain': 'text'
'default': 'blob'
```

## Composition

All these decorators where designed so it's easy to use them together, just stack them! _Note: obviously, the order matters._

```js
import {
  fetchify,
  bodify,
  extractJson,
} from 'fetch-decorators';

class Messages {
  @extractJson
  @bodify
  @fetchify({method: 'POST'})
  post(userId) {
    return `/users/${userId}/messages`;
  }

  // Approximate equivalent without decorators
  // Thanks to ES6, the volume of code is roughly the same
  // But the complexity is higher and you'll probably
  // have a lot of code duplication
  mehPost(userId, data, extraOptions) {
    return fetch(`/users/${userId}/messages`, {
      method: 'POST',
      ...extraOptions,
      body: JSON.stringify(data),
    }).then((response) => response.json());
  }
}

const messagesApi = new Messages();

// Request body, as an object
const message = {
  content: 'Hello World',
  public: true,
  draft: false,
};

// Some extra options
const authHeaders = {
  headers: {
    'X-AUTH-MUCH-SECURE': '123FOO456BAR',
  },
};

messagesApi.post('ArnaudRinquin')(message, authHeaders).then(({response, data}) => {
  // response === the original fetch response
  // data === the JSON object returned by the server
});
```

##  FAQ

> Is it just syntactic sugar?

Yes.

> I have a more complex case where my [ headers are dynamic | I have to change fetch options | whatever ]. How do I do?

Then you should manually write your call to `fetch` instead of shoehorning these decorators in your code.

---
_Source: https://npm.io/package/fetch-decorators · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
