Skip to content

Commit

Permalink
feat: Add noThrow option to NetworkLayer advanced options (thanks @…
Browse files Browse the repository at this point in the history
…jamesone)

* Add noThrow option

* Fix tests + commit fixes

* Make noThrow option optional in Flow

* Rm it.only
  • Loading branch information
jamesone authored and nodkz committed Sep 6, 2018
1 parent 3c130b1 commit 827ea30
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 18 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,21 @@ Middlewares
- `prefix` - prefix message (default: `[RELAY-NETWORK] GRAPHQL SERVER ERROR:`)
- **deferMiddleware** - _experimental_ Right now `deferMiddleware()` just set `defer` as supported option for Relay. So this middleware allow to community play with `defer()` in cases, which was [described by @wincent](https://github.com/facebook/relay/issues/288#issuecomment-199510058).

Advanced options (2nd argument after middlewares)
===========

RelayNetworkLayer may accept additional options:

```js
const middlewares = []; // array of middlewares
const options = {}; // optional advanced options
const network = new RelayNetworkLayer(middlewares, options);
```

Available options:

- **noThrow** - EXPERIMENTAL (May be deprecated in the future) set true to not throw when an error response is given by the server, and to instead handle errors in your app code.

### Example of injecting NetworkLayer with middlewares on the **client side**.
```js
import Relay from 'react-relay';
Expand Down
14 changes: 9 additions & 5 deletions src/__tests__/fetchWithMiddleware.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('fetchWithMiddleware', () => {
it('should make a successfull request without middlewares', async () => {
fetchMock.post('/graphql', { id: 1, data: { user: 123 } });

const data = await fetchWithMiddleware(createMockReq(1), []);
const { data } = await fetchWithMiddleware(createMockReq(1), [], {});
expect(data).toEqual({ user: 123 });
});

Expand All @@ -53,10 +53,14 @@ describe('fetchWithMiddleware', () => {

fetchMock.post('/graphql', { id: 1, data: { num: 1 } });

const data = await fetchWithMiddleware(createMockReq(1), [
numPlus5,
numMultiply10, // should be first, when changing response
]);
const { data } = await fetchWithMiddleware(
createMockReq(1),
[
numPlus5,
numMultiply10, // should be first, when changing response
],
{}
);
expect(data).toEqual({ num: 15 });
});
});
6 changes: 5 additions & 1 deletion src/definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export type RRNLResponseObject = {
statusText: string,
headers: { [name: string]: string },
url: string,
payload: ?GraphQLResponse,
payload?: GraphQLResponse,
};

export type RelayClassicRequest = {
Expand All @@ -71,3 +71,7 @@ export type RelayClassicRequest = {
getVariables: () => Object,
getDebugName: () => string,
};

export type RRNLOptions = {
noThrow?: boolean,
};
18 changes: 15 additions & 3 deletions src/fetchWithMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
RRNLRequestObject,
RRNLResponseObject,
MiddlewareNextFn,
RRNLOptions,
} from './definition';

function runFetch(req: RRNLRequestObject): Promise<RRNLResponseObject> {
Expand Down Expand Up @@ -40,16 +41,27 @@ function runFetch(req: RRNLRequestObject): Promise<RRNLResponseObject> {

export default function fetchWithMiddleware(
req: RRNLRequestObject,
middlewares: Middleware[]
middlewares: Middleware[],
options: RRNLOptions
): Promise<any> {
const wrappedFetch: MiddlewareNextFn = compose(...middlewares)(runFetch);

return wrappedFetch(req).then(res => {
const { payload } = res;
if (!payload || payload.hasOwnProperty('errors') || !payload.hasOwnProperty('data')) {
const { noThrow = false } = options;
const hasErrors =
!payload || payload.hasOwnProperty('errors') || !payload.hasOwnProperty('data');

/** Only throw the Error if noThrow === false */
if (!noThrow && hasErrors) {
throw createRequestError(req, res);
}
return payload.data;

/** Return payload.data as well as the errors (if they exist) */
return {
data: (payload && payload.data) || null,
errors: hasErrors ? createRequestError(req, res) : null,
};
});
}

Expand Down
1 change: 0 additions & 1 deletion src/middleware/__tests__/auth.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ describe('Middleware / auth', () => {
it('should work with mutation', async () => {
const req1 = mockReq();
await rnl.sendMutation(req1);

expect(req1.payload).toEqual({ response: 'PAYLOAD' });
const reqs = fetchMock.calls('/graphql');
expect(reqs).toHaveLength(1);
Expand Down
2 changes: 1 addition & 1 deletion src/relayMutation.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function mutation(
}

return fetchWithMiddleware(req)
.then(data => relayRequest.resolve({ response: data }))
.then(({ data }) => relayRequest.resolve({ response: data }))
.catch(err => {
relayRequest.reject(err);
throw err;
Expand Down
10 changes: 4 additions & 6 deletions src/relayNetworkLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import queries from './relayQueries';
import mutation from './relayMutation';
import fetchWithMiddleware from './fetchWithMiddleware';
import type { Middleware, RelayClassicRequest } from './definition';

export type RRNLOptions = {};
import type { Middleware, RelayClassicRequest, RRNLOptions } from './definition';

export default class RelayNetworkLayer {
_options: RRNLOptions;
Expand All @@ -16,7 +14,7 @@ export default class RelayNetworkLayer {
sendMutation: Function;

constructor(middlewares: Middleware[] | Middleware, options?: RRNLOptions) {
this._options = options || {};
this._options = typeof options === 'object' ? options : {};
this._middlewares = Array.isArray(middlewares) ? middlewares : [middlewares];
this._supportedOptions = [];

Expand All @@ -40,10 +38,10 @@ export default class RelayNetworkLayer {
}

sendQueries(requests: RelayClassicRequest[]): Promise<any> {
return queries(requests, req => fetchWithMiddleware(req, this._middlewares));
return queries(requests, req => fetchWithMiddleware(req, this._middlewares, this._options));
}

sendMutation(request: RelayClassicRequest): Promise<any> {
return mutation(request, req => fetchWithMiddleware(req, this._middlewares));
return mutation(request, req => fetchWithMiddleware(req, this._middlewares, this._options));
}
}
2 changes: 1 addition & 1 deletion src/relayQueries.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function queries(
};

return fetchWithMiddleware(req)
.then(data => relayRequest.resolve({ response: data }))
.then(({ data }) => relayRequest.resolve({ response: data }))
.catch(err => {
relayRequest.reject(err);
throw err;
Expand Down

0 comments on commit 827ea30

Please sign in to comment.