npm package: @nsatosh/redux-ajax-middleware
Description: Redux middleware for handling Ajax
Author: nsatosh
Latest version: 0.0.3

# redux-ajax-middleware

Redux middleware handles XMLHttpRequest.

## Install
```
npm i redux-agent-middleware
```

## Usage
### Setup middleware
``` js
//configureStore.js
import { createStore, applyMiddleware, compose } from 'redux';
import { makeApiMiddleware } from 'redux-agent-middleware';

const finalCreateStore = compose(
  //...
  applyMiddleware(makeApiMiddleware()),
  //...
);
```

### Create action
This middleware runs XMLHttpRequest when action includes `CALL_API` symbol key has passed.
After request, if the action has `ABORT_API` is passed, the middleware cancel existing request.

If either keys have not included, the middleware do nothing.

``` js
//ReportActions.js
import { CALL_API, ABORT_API } from 'redux-agent-middleware';

export function uploadArticle {
  return {
    type: 'REQUEST_UPLOAD_ARTICLE',
    [CALL_API]: {
      endpoint: 'https://localhost:3000/articles',
      method: 'post',
      body: getState => getState().draft,
      onload: xhr => {
        if (xhr.status === 200) {
          return {type: 'RECEIVE_UPLOAD_ARTICLE'};
        } else {
          return {type: 'FAILED_UPLOAD_ARTICLE'};
        }
      },
      onprogress: (xhr, event) => ({
        type: 'PROGRESS_UPLOAD_ARTICLE',
        total: event.total,
        loaded: event.loaded,
      }),
      onerror: {type: 'APPLICATION_ERROR'},
    },
  };
}

export function cancelUploadingArticle {
  return {
    type: 'CANCEL_UPLOAD_ARTICLE',
    [ABORT_API]: true,
  };
}
```

Above `uploadArticle()` invokes actions as belows:

```
// 1st
{
  type: 'REQUEST_UPLOAD_ARTICLE'
}
```
```
// 2nd
{
  type: 'PROGRESS_UPLOAD_ARTICLE',
  total: 1000,
  loaded: 1000
}
```
```
// 3rd
{
  type: 'RECEIVE_UPLOAD_ARTICLE',
}
```

You can abort uploading article by calling `cancelUploadingArticle()`. This invokes action as belows:

```
{
  type: 'CANCEL_UPLOAD_ARTICLE'
}
```

## Reference
### `makeApiMiddleware({xhrIdName})`
Return redux store middleware function.

#### Options
- `xhrIdName` : The action's property key name used for identifying XMLHttpRequest. (default: `'type'`)

### `CALL_API`
CALL_API object has properties used by initializing XMLHttpRequest.

#### `endpoint`
URL endpoint

Query string included.

#### `method`
HTTP method string.

#### `headers`
HTTP headers object.

#### `body`
HTTP body

#### `onprogress`
```
{
  [CALL_API]: {
    //...
    onprogress: (xhr, event) => {

    }
  }
}
```

#### `onload`
#### `onabort`
#### `ontimeout`
#### `onerror`

### `ABORT_API`

## Example: JSON request and response

``` js
function parseJson(type, xhr) {
  let body;
  try {
    body = JSON.parse(xhr.response);
  } catch(e) {
    return {
      type: 'ApplicationError',
      desc: 'Failed to parse response',
    };
  }
  return {type, body};
}

export function uploadArticle {
  return {
    type: 'REQUEST_UPLOAD_ARTICLE',
    [CALL_API]: {
      endpoint: 'https://localhost:3000/articles',
      method: 'post',
      headers: {
        'Content-Type': 'application/json',
      },
      body: getState => JSON.strinfigy(getState().draft),
      onload: xhr => parseJson('RECEIVE_DATA', xhr),
    },
  };
}
```

## Example: Authorization

``` js
export function login {
  return {
    type: 'REQUEST_LOGIN',
    [CALL_API]: {
      endpoint: 'https://localhost:3000/login',
      method: 'post',
      headers: {
        'Content-Type': 'application/json',
      },
      body: getState => JSON.strinfigy(getState().loginForm),
      onload: xhr => {
        if (xhr.status === 200) {
          return {
            type: 'RECEIVE_LOGIN',
            token: xhr.getResponseHeader('X-Authorization'),
          };
        }
        //...
      },
    },
  };
}
```


## TODO
- Support blob, file, ...

## License
MIT