Skip to content

Commit

Permalink
feat(UrlMiddleware): add mode, cache, redirect options for fetch
Browse files Browse the repository at this point in the history
  • Loading branch information
nodkz committed Feb 28, 2018
1 parent 6f7c3e9 commit ba4287f
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 67 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@
"Blob": true,
"Class": true,
"window": true,
"$PropertyType": true
}
}
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Middlewares
- `method` - string, for request method type (default: `POST`)
- headers - Object with headers for fetch. Can be Promise or function(req).
- credentials - string, setting for fetch method, eg. 'same-origin' (default: empty).
- also you may provide `mode`, `cache`, `redirect` options for fetch method, for details see [fetch spec](https://fetch.spec.whatwg.org/#requests).
- **cacheMiddleware** - for caching same queries you may use this middleware. It will skip (do not cache) mutations and FormData requests.
- `size` - max number of request in cache, least-recently *updated* entries purged first (default: `100`).
- `ttl` - number in milliseconds, how long records stay valid in cache (default: `900000`, 15 minutes).
Expand Down Expand Up @@ -153,7 +154,7 @@ const network = new RelayNetworkLayer([
req.fetchOpts.headers['X-Request-ID'] = uuid.v4(); // add `X-Request-ID` to request headers
req.fetchOpts.credentials = 'same-origin'; // allow to send cookies (sending credentials to same domains)
// req.fetchOpts.credentials = 'include'; // allow to send cookies for CORS (sending credentials to other domains)

console.log('RelayRequest', req);

const res = await next(req);
Expand Down
5 changes: 5 additions & 0 deletions src/definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export type FetchOpts = {
method: 'POST' | 'GET',
headers: { [name: string]: string },
body: string | FormData,
// Avaliable request modes in fetch options. For details see https://fetch.spec.whatwg.org/#requests
credentials?: 'same-origin' | 'include' | 'omit',
mode?: 'cors' | 'websocket' | 'navigate' | 'no-cors' | 'same-origin',
cache?: 'default' | 'no-store' | 'reload' | 'no-cache' | 'force-cache' | 'only-if-cached',
redirect?: 'follow' | 'error' | 'manual',
[name: string]: mixed,
};

Expand Down
52 changes: 0 additions & 52 deletions src/middlewares/__tests__/__snapshots__/url-test.js.snap
Original file line number Diff line number Diff line change
@@ -1,57 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`middlewares/url \`credentials\` option 1`] = `
Object {
"body": "{\\"id\\":\\"1\\",\\"query\\":\\"\\",\\"variables\\":{}}",
"credentials": "same-origin",
"headers": Object {
"Accept": "*/*",
"Content-Type": "application/json",
},
"method": "POST",
"url": "/credentials_url",
}
`;

exports[`middlewares/url \`headers\` option as Object 1`] = `
Object {
"body": "{\\"id\\":\\"1\\",\\"query\\":\\"\\",\\"variables\\":{}}",
"headers": Object {
"Accept": "*/*",
"Content-Type": "application/json",
"custom-header": "123",
},
"method": "POST",
"url": "/headers_url",
}
`;

exports[`middlewares/url \`headers\` option as thunk 1`] = `
Object {
"body": "{\\"id\\":\\"1\\",\\"query\\":\\"\\",\\"variables\\":{}}",
"headers": Object {
"Accept": "*/*",
"Content-Type": "application/json",
"thunk-header": "333",
},
"method": "POST",
"url": "/headers_thunk",
}
`;

exports[`middlewares/url \`headers\` option as thunk with Promise 1`] = `
Object {
"body": "{\\"id\\":\\"1\\",\\"query\\":\\"\\",\\"variables\\":{}}",
"headers": Object {
"Accept": "*/*",
"Content-Type": "application/json",
"thunk-header": "as promise",
},
"method": "POST",
"url": "/headers_thunk_promise",
}
`;

exports[`middlewares/url \`method\` option 1`] = `
Object {
"body": "{\\"id\\":\\"1\\",\\"query\\":\\"\\",\\"variables\\":{}}",
Expand Down
56 changes: 52 additions & 4 deletions src/middlewares/__tests__/url-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,11 @@ describe('middlewares/url', () => {
const req = mockReq(1);
const res = await req.execute(rnl);
expect(res.data).toBe('PAYLOAD4');
expect(fetchMock.lastOptions()).toMatchSnapshot();
expect(fetchMock.lastOptions().headers).toEqual(
expect.objectContaining({
'custom-header': '123',
})
);
});

it('`headers` option as thunk', async () => {
Expand All @@ -140,7 +144,11 @@ describe('middlewares/url', () => {
const req = mockReq(1);
const res = await req.execute(rnl);
expect(res.data).toBe('PAYLOAD5');
expect(fetchMock.lastOptions()).toMatchSnapshot();
expect(fetchMock.lastOptions().headers).toEqual(
expect.objectContaining({
'thunk-header': '333',
})
);
});

it('`headers` option as thunk with Promise', async () => {
Expand All @@ -165,7 +173,11 @@ describe('middlewares/url', () => {
const req = mockReq(1);
const res = await req.execute(rnl);
expect(res.data).toBe('PAYLOAD5');
expect(fetchMock.lastOptions()).toMatchSnapshot();
expect(fetchMock.lastOptions().headers).toEqual(
expect.objectContaining({
'thunk-header': 'as promise',
})
);
});

it('`credentials` option', async () => {
Expand All @@ -187,6 +199,42 @@ describe('middlewares/url', () => {
const req = mockReq(1);
const res = await req.execute(rnl);
expect(res.data).toBe('PAYLOAD6');
expect(fetchMock.lastOptions()).toMatchSnapshot();
expect(fetchMock.lastOptions()).toEqual(
expect.objectContaining({
credentials: 'same-origin',
})
);
});

it('other fetch options', async () => {
fetchMock.mock({
matcher: '/fetch',
response: {
status: 200,
body: { data: 'PAYLOAD7' },
},
method: 'POST',
});

const rnl = new RelayNetworkLayer([
urlMiddleware({
url: '/fetch',
credentials: 'include',
mode: 'cors',
cache: 'no-store',
redirect: 'follow',
}),
]);
const req = mockReq(1);
const res = await req.execute(rnl);
expect(res.data).toBe('PAYLOAD7');
expect(fetchMock.lastOptions()).toEqual(
expect.objectContaining({
credentials: 'include',
mode: 'cors',
cache: 'no-store',
redirect: 'follow',
})
);
});
});
22 changes: 12 additions & 10 deletions src/middlewares/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,23 @@

import { isFunction } from '../utils';
import type RelayRequest from '../RelayRequest';
import type { Middleware } from '../definition';
import type { Middleware, FetchOpts } from '../definition';

type Headers = { [name: string]: string };

export type UrlMiddlewareOpts = {
url: string | Promise<string> | ((req: RelayRequest) => string | Promise<string>),
method?: 'POST' | 'GET',
headers?: Headers | Promise<Headers> | ((req: RelayRequest) => Headers | Promise<Headers>),
credentials?: 'same-origin' | string,
// Avaliable request modes in fetch options. For details see https://fetch.spec.whatwg.org/#requests
credentials?: $PropertyType<FetchOpts, 'credentials'>,
mode?: $PropertyType<FetchOpts, 'mode'>,
cache?: $PropertyType<FetchOpts, 'cache'>,
redirect?: $PropertyType<FetchOpts, 'redirect'>,
};

export default function urlMiddleware(opts?: UrlMiddlewareOpts): Middleware {
const { url, headers, method = 'POST', credentials } = opts || {};
const { url, headers, method = 'POST', credentials, mode, cache, redirect } = opts || {};
const urlOrThunk: any = url || '/graphql';
const headersOrThunk: any = headers;

Expand All @@ -28,13 +32,11 @@ export default function urlMiddleware(opts?: UrlMiddlewareOpts): Middleware {
: headersOrThunk);
}

if (method) {
req.fetchOpts.method = method;
}

if (credentials) {
req.fetchOpts.credentials = credentials;
}
if (method) req.fetchOpts.method = method;
if (credentials) req.fetchOpts.credentials = credentials;
if (mode) req.fetchOpts.mode = mode;
if (cache) req.fetchOpts.cache = cache;
if (redirect) req.fetchOpts.redirect = redirect;

return next(req);
};
Expand Down

0 comments on commit ba4287f

Please sign in to comment.