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

feat(mapOptionToKey): provide first helper #87

Merged
merged 2 commits into from
Oct 23, 2023
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
59 changes: 52 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@
const controller = new AbortController();
useFetchye('http://example.com/api/books', { signal: controller.signal });

useEffect(() => () => controller.abort(), []);

Check warning on line 353 in README.md

View workflow job for this annotation

GitHub Actions / Node 12.x

React Hook useEffect has a missing dependency: 'controller'. Either include it or remove the dependency array

Check warning on line 353 in README.md

View workflow job for this annotation

GitHub Actions / Node 14.x

React Hook useEffect has a missing dependency: 'controller'. Either include it or remove the dependency array

Check warning on line 353 in README.md

View workflow job for this annotation

GitHub Actions / Node 16.x

React Hook useEffect has a missing dependency: 'controller'. Either include it or remove the dependency array

Check warning on line 353 in README.md

View workflow job for this annotation

GitHub Actions / Node 18.x

React Hook useEffect has a missing dependency: 'controller'. Either include it or remove the dependency array

return (
<div>
Expand Down Expand Up @@ -597,20 +597,17 @@

This function will be called, to re-make the headers just before an API call is made, even when you call `run`.

Note: If you don't want the dynamic headers to result in a cache miss, you must remove the keys of the dynamic headers from the options using `mapOptionsToKey` (see example below).
Note: If you don't want the dynamic headers to result in a cache miss, you must remove the keys of the dynamic headers from the options using `mapOptionsToKey` (see example below that uses the `ignoreHeadersByKey` helper).

```jsx
import React from 'react';
import { useFetchye } from 'fetchye';
import { useFetchye, ignoreHeadersByKey } from 'fetchye';
import uuid from 'uuid';

const BookList = () => {
const { isLoading, data } = useFetchye('http://example.com/api/books/', {
// remove the 'correlationId' header from the headers, as its the only dynamic header
mapOptionsToKey: ({ headers: { correlationId, ...headers }, ...options }) => ({
...options,
headers,
}),
mapOptionsToKey: ignoreHeadersByKey(['correlationId']),
headers: () => ({
// static headers are still fine, and can be specified here like normal
staticHeader: 'staticValue',
Expand Down Expand Up @@ -810,6 +807,8 @@
* [`DELETE_DATA`](#delete_data)
* [`ERROR`](#error)
* [`CLEAR_ERROR`](#clear_error)
* [`mapOptionToKey Helpers`](#mapoptiontokey-helpers)
* [`ignoreHeadersByKey`](#ignoreheadersbykey)

### `useFetchye`

Expand All @@ -833,7 +832,7 @@

| name | type | required | description |
|--------------------|-------------------------------------------------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `mapOptionsToKey` | `(options: Options) => transformedOptions` | `false` | A function that maps options to the key that will become part of the cache key |
| `mapOptionsToKey` | `(options: Options) => transformedOptions` | `false` | A function that maps options to the key that will become part of the cache key. See below for a list of mapOptionsToKey helpers. |
| `mapKeyToCacheKey` | `(key: String, options: Options) => cacheKey: String` | `false` | A function that maps the key for use as the cacheKey allowing direct control of the cacheKey |
| `defer` | `Boolean` | `false` | Prevents execution of `useFetchye` on each render in favor of using the returned `run` function. *Defaults to `false`* |
| `initialData` | `Object` | `false` | Seeds the initial data on first render of `useFetchye` to accomodate server side rendering *Defaults to `undefined`* |
Expand Down Expand Up @@ -1221,6 +1220,52 @@
|---|---|---|
| `hash` | `String` | The hash value generated by [`object-hash`](https://github.com/puleos/object-hash) package for the query |

### mapOptionToKey Helpers
These helpers provide a more compact and simple way of common transforms.

There is currently one helper.

#### ignoreHeadersByKey

**Shape**

`(String[]) => mapOptionsToKeyFunction`

**Arguments**

| name | type | required | description |
|--------|-----------------|----------|--------------------------------------------------------------------------------------------------|
| `keys` | `Array<String>` | `true` | creates a mapOptionsToKey function that removes headers whose keys match the specified keys |

**Returns**

| name | type | description |
|----------------------------|---------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| `mapOptionsToKey Function` | `mapOptionsToKeyFunction` | A function to be passed to the mapOptionsToKey option in useFetchye, or the `fetchye` function made by `makeServerFetchye`. |

**Example**

```jsx
import React from 'react';
import { useFetchye, ignoreHeadersByKey } from 'fetchye';

const BookList = ({ locale }) => {
const { isLoading, data } = useFetchye('http://example.com/api/books/', {
// remove the 'locale' header from the headers when building the cache key
mapOptionsToKey: ignoreHeadersByKey(['locale']),
headers: { locale },
});

// ... rest of component
};

export default BookList;
```





## 📢 Mission

The Fetchye project wishes to bring a more flexible central caching experience
Expand Down
1 change: 1 addition & 0 deletions packages/fetchye/__tests__/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe('index', () => {
Array [
"FetchyeProvider",
"SimpleCache",
"ignoreHeadersByKey",
"makeServerFetchye",
"useFetchye",
]
Expand Down
54 changes: 54 additions & 0 deletions packages/fetchye/__tests__/mapOptionsToKeyHelpers.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2023 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import { ignoreHeadersByKey } from '../src/mapOptionsToKeyHelpers';

describe('mapOptionsToKeyHelpers', () => {
describe('ignoreHeadersByKey', () => {
it('should do nothing if the header key is not present', () => {
expect(ignoreHeadersByKey([])({})).toEqual({});
expect(ignoreHeadersByKey([])(
{ otherKey: 'otherKeyValue' }
)).toEqual(
{ otherKey: 'otherKeyValue' }
);
});
it('should do nothing if the header key is present, but the mentioned keys to remove are not present', () => {
expect(ignoreHeadersByKey(['removeHeaderKey'])(
{ headers: { preserveHeaderKey: 'preserveHeaderKeyValue' } }
)).toEqual(
{ headers: { preserveHeaderKey: 'preserveHeaderKeyValue' } }
);
expect(ignoreHeadersByKey(['removeHeaderKey'])(
{ otherKey: 'otherKeyValue', headers: { preserveHeaderKey: 'preserveHeaderKeyValue' } }
)).toEqual(
{ otherKey: 'otherKeyValue', headers: { preserveHeaderKey: 'preserveHeaderKeyValue' } }
);
});
it('should remove the mentioned key if its present in the headers', () => {
expect(ignoreHeadersByKey(['removeHeaderKey'])(
{ headers: { preserveHeaderKey: 'preserveHeaderKeyValue', removeHeaderKey: 'removeHeaderKeyValue' } }
)).toEqual(
{ headers: { preserveHeaderKey: 'preserveHeaderKeyValue' } }
);
expect(ignoreHeadersByKey(['removeHeaderKey'])(
{ otherKey: 'otherKeyValue', headers: { preserveHeaderKey: 'preserveHeaderKeyValue', removeHeaderKey: 'removeHeaderKeyValue' } }
)).toEqual(
{ otherKey: 'otherKeyValue', headers: { preserveHeaderKey: 'preserveHeaderKeyValue' } }
);
});
});
});
2 changes: 2 additions & 0 deletions packages/fetchye/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ import useFetchye from './useFetchye';
import makeServerFetchye from './makeServerFetchye';
import FetchyeProvider from './FetchyeProvider';
import SimpleCache from './SimpleCache';
import { ignoreHeadersByKey } from './mapOptionsToKeyHelpers';

export {
useFetchye,
makeServerFetchye,
FetchyeProvider,
SimpleCache,
ignoreHeadersByKey,
};
32 changes: 32 additions & 0 deletions packages/fetchye/src/mapOptionsToKeyHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2023 American Express Travel Related Services Company, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

const filterObjectByKeys = (object, keys) => Object.keys(object)
.filter((key) => !keys.includes(key))
.reduce((acc, key) => {
// mutating accumulator to prevent many, many object allocations
acc[key] = object[key];
return acc;
}, {});

export const ignoreHeadersByKey = (keys) => ({ headers, ...options }) => (
headers
? {
...options,
headers: filterObjectByKeys(headers, keys),
}
: { ...options }
);
Loading