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

Add noThrow option to NetworkLayer advanced options #61

Merged
merged 4 commits into from
Sep 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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