Skip to content
This repository was archived by the owner on May 17, 2019. It is now read-only.

Commit 4b7d9e3

Browse files
ganemonefusion-bot[bot]
authored and
fusion-bot[bot]
committed
Update underlying version of fusion-plugin-rpc
#119
1 parent ecc0fc6 commit 4b7d9e3

File tree

5 files changed

+898
-1035
lines changed

5 files changed

+898
-1035
lines changed

README.md

Lines changed: 110 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
[![Build status](https://badge.buildkite.com/c16ece6ba0a81b30d11d69cb90b8f4d77a0967860144d12f44.svg?branch=master)](https://buildkite.com/uberopensource/fusion-plugin-rpc-redux-react)
44

5-
Provides a higher order component that connects RPC methods to Redux as well as React component props
5+
Provides a higher order component that connects RPC methods to Redux as well as
6+
React component props
67

78
RPC is a natural way of expressing that a server-side function should be run in response to a client-side function call. Unlike [RESTful architectures](https://en.wikipedia.org/wiki/Representational_state_transfer), RPC-based architectures are not required to conform to statelessness constraints and are free to return session-scoped data. Additionally, the semantics of RPC calls are not constrained by the availability of suitably-descriptive HTTP methods and RPC calls can express complex state change requests more naturally as verbs (e.g. `returnProduct(id)`) rather than object-orientation (e.g. `PATCH /api/orders/:id`).
89

@@ -18,6 +19,7 @@ RPC is a natural way of expressing that a server-side function should be run in
1819
* [Dependencies](#dependencies)
1920
* [`withRPCRedux`](#withrpcredux)
2021
* [`withRPCReactor`](#withrpcreactor)
22+
* [`ResponseError`](#responseerror)
2123
* [`mock`](#mock)
2224
* [Other examples](#other-examples)
2325

@@ -117,21 +119,24 @@ export default () => {
117119
import RPC from 'fusion-plugin-rpc-redux-react';
118120
```
119121

120-
The plugin. Typically it should be registered to [`RPCToken`](#rpctoken). Installs an RPC provider at the root of the React tree.
122+
The plugin. Typically it should be registered to [`RPCToken`](#rpctoken).
123+
Installs an RPC provider at the root of the React tree.
121124

122125
###### `RPCToken`
123126

124127
```js
125128
import {RPCToken} from 'fusion-plugin-rpc-redux-react';
126129
```
127130

128-
The canonical token for the RPC plugin. Typically, it should be registered with the [RPC](#rpc) plugin.
131+
The canonical token for the RPC plugin. Typically, it should be registered with
132+
the [RPC](#rpc) plugin.
129133

130134
#### Dependencies
131135

132136
##### `UniversalEventsToken`
133137

134-
Required. See [https://github.com/fusionjs/fusion-plugin-universal-events#api](https://github.com/fusionjs/fusion-plugin-universal-events#api)
138+
Required. See
139+
[https://github.com/fusionjs/fusion-plugin-universal-events#api](https://github.com/fusionjs/fusion-plugin-universal-events#api)
135140

136141
##### `RPCHandlersToken`
137142

@@ -147,19 +152,23 @@ Configures what RPC handlers exist. Required. Server-only.
147152
type RPCHandlers = {[string]: (rpcArgs: Object, ctx: Context) => Promise<Object>}
148153
```
149154

150-
You can register a value of type `RPCHandlers` or a Plugin that provides a value of type `RPCHandlers`.
155+
You can register a value of type `RPCHandlers` or a Plugin that provides a value
156+
of type `RPCHandlers`.
151157

152158
##### `FetchToken`
153159

154-
Required. Browser-only. See [https://github.com/fusionjs/fusion-tokens#fetchtoken](https://github.com/fusionjs/fusion-tokens#fetchtoken)
160+
Required. Browser-only. See
161+
[https://github.com/fusionjs/fusion-tokens#fetchtoken](https://github.com/fusionjs/fusion-tokens#fetchtoken)
155162

156163
##### `ReduxToken`
157164

158-
Required. See [https://github.com/fusionjs/fusion-plugin-react-redux](https://github.com/fusionjs/fusion-plugin-react-redux)
165+
Required. See
166+
[https://github.com/fusionjs/fusion-plugin-react-redux](https://github.com/fusionjs/fusion-plugin-react-redux)
159167

160168
##### `ReducerToken`
161169

162-
Required. See [https://github.com/fusionjs/fusion-plugin-react-redux](https://github.com/fusionjs/fusion-plugin-react-redux)
170+
Required. See
171+
[https://github.com/fusionjs/fusion-plugin-react-redux](https://github.com/fusionjs/fusion-plugin-react-redux)
163172

164173
---
165174

@@ -169,7 +178,9 @@ Required. See [https://github.com/fusionjs/fusion-plugin-react-redux](https://gi
169178
import {withRPCRedux} from 'fusion-plugin-rpc-redux-react';
170179
```
171180

172-
Creates a higher order component with a prop mapped to the given RPC method. It can additionally configure the mapped method with parameters from state or from a transformation function.
181+
Creates a higher order component with a prop mapped to the given RPC method. It
182+
can additionally configure the mapped method with parameters from state or from
183+
a transformation function.
173184

174185
```js
175186
const hoc:HOC = withRPCRedux(rpcId: string, {
@@ -180,9 +191,12 @@ const hoc:HOC = withRPCRedux(rpcId: string, {
180191

181192
```
182193
183-
* `rpcId: string` - The name of the RPC method to expose in the component's props
184-
* `propName: ?string` - Optional. The name of the prop. Defaults to the same as `rpcId`
185-
* `mapStateToParams: ?(state: any) => any` - populate the RPC request with parameters from Redux state
194+
* `rpcId: string` - The name of the RPC method to expose in the component's
195+
props
196+
* `propName: ?string` - Optional. The name of the prop. Defaults to the same as
197+
`rpcId`
198+
* `mapStateToParams: ?(state: any) => any` - populate the RPC request with
199+
parameters from Redux state
186200
* `transformParams: ?(params: any) => any` - transforms the params
187201
* returns `hoc: Component => Component`
188202
@@ -206,22 +220,51 @@ const hoc:HOC = withRPCReactor(rpcId: string, {
206220
});
207221
```
208222
209-
* `rpcId: string` - The name of the RPC method to expose in the component's props
210-
* `start: ?(state: any, action: Object) => any` - A reducer to run when the RPC call is made
211-
* `success: ?(state: any, action: Object) => any` - A reducer to run when the RPC call succeeds
212-
* `failure: ?(state: any, action: Object) => any` - A reducer to run when the RPC call fails
213-
* `propName: ?string` - Optional. The name of the prop. Defaults to the same as `rpcId`
214-
* `mapStateToParams: ?(state: any) => any` - populate the RPC request with parameters from Redux state
223+
* `rpcId: string` - The name of the RPC method to expose in the component's
224+
props
225+
* `start: ?(state: any, action: Object) => any` - A reducer to run when the RPC
226+
call is made
227+
* `success: ?(state: any, action: Object) => any` - A reducer to run when the
228+
RPC call succeeds
229+
* `failure: ?(state: any, action: Object) => any` - A reducer to run when the
230+
RPC call fails
231+
* `propName: ?string` - Optional. The name of the prop. Defaults to the same as
232+
`rpcId`
233+
* `mapStateToParams: ?(state: any) => any` - populate the RPC request with
234+
parameters from Redux state
215235
* `transformParams: ?(params: any) => any` - transforms the params
216236
* returns `hoc: Component => Component`
217237
238+
#### ResponseError
239+
240+
Use the `ResponseError` error subclass for sending error responses. If this
241+
error class is not used, a generic message will be sent to the client.
242+
243+
```js
244+
import {ResponseError} from 'fusion-plugin-rpc';
245+
246+
function testHandler() {
247+
try {
248+
doThing();
249+
} catch (e) {
250+
const error = new ResponseError('Failed to do thing');
251+
error.code = 'DOTHING';
252+
error.meta = {
253+
custom: 'metadata',
254+
};
255+
throw error;
256+
}
257+
}
258+
```
259+
218260
#### mock
219261
220262
```js
221263
import {mock as MockRPC} from 'fusion-plugin-rpc-redux-react';
222264
```
223265
224-
The package also exports a mock RPC plugin which can be useful for testing. For example:
266+
The package also exports a mock RPC plugin which can be useful for testing. For
267+
example:
225268
226269
```js
227270
app.register(RPCToken, mock);
@@ -233,11 +276,14 @@ app.register(RPCToken, mock);
233276
234277
### Usage with Reactors
235278
236-
[`redux-reactors`](https://github.com/ganemone/redux-reactors) is a library that allows you to colocate Redux actions and reducers
279+
[`redux-reactors`](https://github.com/ganemone/redux-reactors) is a library that
280+
allows you to colocate Redux actions and reducers
237281
238-
The `fusion-plugin-rpc-redux-react` package provides a `withRPCReactor` HOC which facilitates implementing a Redux store using reactors.
282+
The `fusion-plugin-rpc-redux-react` package provides a `withRPCReactor` HOC
283+
which facilitates implementing a Redux store using reactors.
239284
240-
To use it, register the `fusion-plugin-react-redux` plugin with `reactorEnhancer` from `redux-reactors`:
285+
To use it, register the `fusion-plugin-react-redux` plugin with
286+
`reactorEnhancer` from `redux-reactors`:
241287
242288
```js
243289
// src/main.js
@@ -276,7 +322,9 @@ export default {
276322
}
277323
```
278324
279-
Because `redux-reactors` is implemented as a Redux enhancer, it doesn't require building reducers in the traditional Redux way. Thus, the root reducer can simply be the identity function:
325+
Because `redux-reactors` is implemented as a Redux enhancer, it doesn't require
326+
building reducers in the traditional Redux way. Thus, the root reducer can
327+
simply be the identity function:
280328
281329
```js
282330
// src/redux.js
@@ -296,15 +344,24 @@ export const incrementReactor = withRPCReactor('increment', {
296344
});
297345
```
298346
299-
`incrementReactor: Component => Component` is a React HOC. It defines three actions: `start`, `success` and `failure`, which correspond to the respective statuses of a HTTP request.
347+
`incrementReactor: Component => Component` is a React HOC. It defines three
348+
actions: `start`, `success` and `failure`, which correspond to the respective
349+
statuses of a HTTP request.
300350
301-
In the example above, when `increment` is called, the `start` action is dispatched, which runs a reducer that sets `state.loading` to true, `state.error` to false and keeps `state.count` intact. If the request completes successfully, `state.loading` is set to false, and `state.count` is updated with a new value. Similarly, if the request fails, `state.error` is set.
351+
In the example above, when `increment` is called, the `start` action is
352+
dispatched, which runs a reducer that sets `state.loading` to true,
353+
`state.error` to false and keeps `state.count` intact. If the request completes
354+
successfully, `state.loading` is set to false, and `state.count` is updated with
355+
a new value. Similarly, if the request fails, `state.error` is set.
302356
303-
In addition to defining action/reducer pairs, the `incrementReactor` HOC also maps RPC methods to React props.
357+
In addition to defining action/reducer pairs, the `incrementReactor` HOC also
358+
maps RPC methods to React props.
304359
305-
Reactors typically need to be used in conjunction with `connect` from `react-redux`, in order to map state to React.
360+
Reactors typically need to be used in conjunction with `connect` from
361+
`react-redux`, in order to map state to React.
306362
307-
Below is an example of consuming the state and RPC methods that are made available from the Redux store and the RPC plugin.
363+
Below is an example of consuming the state and RPC methods that are made
364+
available from the Redux store and the RPC plugin.
308365
309366
```js
310367
// src/components/example.js
@@ -335,10 +392,28 @@ export default hoc(Example);
335392
336393
### Differences between reactors and vanilla Redux
337394
338-
Redux colocates all valid actions in a respective "slot" in the state tree, and colocates the structuring of the state tree via helpers such as `combineReducers`. This means that a reducer can be unit tested by simply calling the reducer with one of the valid actions, without having any effect on any other state that might exist in the app. The downside is that if an action needs to modify multiple "slots" in the state tree, it can be tedious to find all transformations pertaining to any given action.
339-
340-
Another point worth mentioning is that with traditional reducers, it's possible to refactor the state tree in such a way that doesn't make any changes to reducers or components (albeit it does require changing the reducer composition chain as well as all relevant `mapStateToProps` functions).
341-
342-
Reactors, on the other hand, colocate a single reducer to a single action, so all state transformations pertaining to any given action are handled by a single function. This comes at the cost of flexibility: it's no longer possible to refactor the shape of the state tree without changing every affectd reducer, and it's also possible to affect unrelated parts of the state tree, for example missing properties due to an overly conservative object assignment.
343-
344-
However doing large refactors to the shape of the state tree isn't necessarily all that common and it's often more intuitive to see all possible state transformations for a given action in a single place. In addition to creating less boilerplate, this pattern leads to similarly intuitive tests that are also colocated by action.
395+
Redux colocates all valid actions in a respective "slot" in the state tree, and
396+
colocates the structuring of the state tree via helpers such as
397+
`combineReducers`. This means that a reducer can be unit tested by simply
398+
calling the reducer with one of the valid actions, without having any effect on
399+
any other state that might exist in the app. The downside is that if an action
400+
needs to modify multiple "slots" in the state tree, it can be tedious to find
401+
all transformations pertaining to any given action.
402+
403+
Another point worth mentioning is that with traditional reducers, it's possible
404+
to refactor the state tree in such a way that doesn't make any changes to
405+
reducers or components (albeit it does require changing the reducer composition
406+
chain as well as all relevant `mapStateToProps` functions).
407+
408+
Reactors, on the other hand, colocate a single reducer to a single action, so
409+
all state transformations pertaining to any given action are handled by a single
410+
function. This comes at the cost of flexibility: it's no longer possible to
411+
refactor the shape of the state tree without changing every affectd reducer, and
412+
it's also possible to affect unrelated parts of the state tree, for example
413+
missing properties due to an overly conservative object assignment.
414+
415+
However doing large refactors to the shape of the state tree isn't necessarily
416+
all that common and it's often more intuitive to see all possible state
417+
transformations for a given action in a single place. In addition to creating
418+
less boilerplate, this pattern leads to similarly intuitive tests that are also
419+
colocated by action.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"./dist/browser.es2015.es.js": "./dist/browser.es2017.es.js"
2424
},
2525
"dependencies": {
26-
"fusion-plugin-rpc": "^1.2.2",
26+
"fusion-plugin-rpc": "^2.0.0",
2727
"fusion-rpc-redux": "^1.1.2"
2828
},
2929
"peerDependencies": {
@@ -68,7 +68,8 @@
6868
"lint": "eslint . --ignore-path .gitignore",
6969
"transpile": "npm run clean && cup build",
7070
"build-test": "rm -rf dist-tests && cup build-tests",
71-
"just-test": "node_modules/.bin/unitest --browser=dist-tests/browser.js --node=dist-tests/node.js",
71+
"just-test":
72+
"node_modules/.bin/unitest --browser=dist-tests/browser.js --node=dist-tests/node.js",
7273
"test": "npm run build-test && npm run just-test",
7374
"cover": "npm run build-test && nyc npm run just-test",
7475
"prepublish": "npm run transpile"

src/__tests__/index.node.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {getService} from 'fusion-test-utils';
1717
import {UniversalEventsToken} from 'fusion-plugin-universal-events';
1818

1919
import Plugin from '../plugin';
20-
import {mock} from '../index';
20+
import {mock, ResponseError} from '../index';
2121
import {withRPCRedux, withRPCReactor} from '../hoc';
2222

2323
/* Test helpers */
@@ -145,3 +145,9 @@ test('withRPCReactor hoc', t => {
145145
rendered.props.test('test-args');
146146
t.end();
147147
});
148+
149+
test('ResponseError', t => {
150+
const e = new ResponseError('test');
151+
t.ok(e instanceof Error);
152+
t.end();
153+
});

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
BodyParserOptionsToken,
1111
RPCToken,
1212
RPCHandlersToken,
13+
ResponseError,
1314
} from 'fusion-plugin-rpc';
1415
import {createRPCReducer} from 'fusion-rpc-redux';
1516
import {withRPCRedux, withRPCReactor} from './hoc';
@@ -18,6 +19,7 @@ import plugin, {mock} from './plugin';
1819
export default plugin;
1920
export {
2021
BodyParserOptionsToken,
22+
ResponseError,
2123
createRPCReducer,
2224
mock,
2325
RPCToken,

0 commit comments

Comments
 (0)