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

Advanced middleware feature #23

Merged
merged 9 commits into from
Mar 19, 2017
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,53 @@ The result of the promise returned by `mutateAsync` will be the following object

Similarly to how mutations are triggered by dispatching `mutateAsync` actions, you can trigger requests by dispatching `requestAsync` actions with a request query config.

### Usage without superagent with `redux-query/advanced`

By default, `redux-query` makes XHR requests using the [superagent](https://github.com/visionmedia/superagent) library. If you'd rather use a different library for making requests, you can use the `redux-query`'s "advanced" mode by importing from `redux-query/advanced` instead of `redux-query`.

Note: The default [`queryMiddleware`](./src/middleware/query.js) exported from the main `redux-query` entry point is simply a [superagent adapter](./src/adapters/superagent.js) bound to `queryMiddlewareAdvanced`.

Example `queryMiddlewareAdvanced` usage:

```javascript
import { applyMiddleware, createStore, combineReducers } from 'redux';
import { entitiesReducer, queriesReducer, queryMiddlewareAdvanced } from 'redux-query/advanced';

// A function that takes a url, method, and other options. This function should return an object
// with two required properties: execute and abort.
import myNetworkAdapter from './network-adapter';

export const getQueries = (state) => state.queries;
export const getEntities = (state) => state.entities;

const reducer = combineReducers({
entities: entitiesReducer,
queries: queriesReducer,
});

const store = createStore(
reducer,
applyMiddleware(queryMiddlewareAdvanced(myNetworkAdapter)(getQueries, getEntities))
);
```

#### Network adapters

You must provide a function to `queryMiddlewareAdvanced` that adheres to the following `NetworkAdapter` interface:

```javascript
type NetworkAdapter = (
url: string,
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
config?: { body?: string | Object, headers?: Object, credentials?: 'omit' | 'include' } = {},
) => Adapter;

type NetworkRequest = {
execute: (callback: (err: any, resStatus: number, resBody: ?Object, resText: string) => void) => void,
abort: () => void,
};
```

## Example

A fork of the `redux` [Async](https://github.com/reactjs/redux/tree/master/examples/async) example is included. To run, first build the package:
Expand Down
1 change: 1 addition & 0 deletions advanced.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/commonjs/advanced');
49 changes: 49 additions & 0 deletions src/adapters/superagent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import superagent from 'superagent';
import * as httpMethods from '../constants/http-methods';

export const createRequest = (url, method) => {
switch (method) {
case httpMethods.GET:
return superagent.get(url);
case httpMethods.POST:
return superagent.post(url);
case httpMethods.PUT:
return superagent.put(url);
case httpMethods.PATCH:
return superagent.patch(url);
case httpMethods.DELETE:
return superagent.del(url);
default:
throw new Error(`Unsupported HTTP method: ${method}`);
}
};

const superagentNetworkAdapter = (url, method, { body, headers, credentials } = {}) => {
const request = createRequest(url, method);

if (body) {
request.send(body);
}

if (headers) {
request.set(headers);
}

if (credentials === 'include') {
request.withCredentials();
}

const execute = (cb) => request.end((err, response) => {
const resStatus = (response && response.status) || 0;
const resBody = (response && response.body) || undefined;
const resText = (response && response.text) || undefined;

cb(err, resStatus, resBody, resText);
});

const abort = () => request.abort();

return { execute, abort };
};

export default superagentNetworkAdapter;
12 changes: 12 additions & 0 deletions src/advanced.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as actions from './actions';
import * as actionTypes from './constants/action-types';
import * as httpMethods from './constants/http-methods';
import * as querySelectors from './selectors/query';

export { default as connectRequest } from './components/connect-request';
export { getQueryKey, reconcileQueryKey } from './lib/query-key';
export { default as queriesReducer } from './reducers/queries';
export { default as entitiesReducer } from './reducers/entities';
export { default as queryMiddlewareAdvanced } from './middleware/query-advanced';
export { cancelQuery, mutateAsync, requestAsync, removeEntities, removeEntity } from './actions';
export { actions, actionTypes, httpMethods, querySelectors };
Loading