diff --git a/README.md b/README.md index 5a402f9..5f92e5a 100644 --- a/README.md +++ b/README.md @@ -207,7 +207,7 @@ const MyComponent = () => { npm i -S fetchye fetchye-one-app ``` -`fetchye-one-app` provides pre-configured `provider`, `cache`, `makeOneServerFetchye` +`fetchye-one-app` provides pre-configured `provider`, `cache`, `oneFetchye` and `oneCacheSelector` to ensure that all modules use the same cache and reduce the chance for cache misses. These all have restricted APIs to reduce the chance for misconfiguration however if you require more control/customization use [`ImmutableCache`](#immutablecache), [`FetchyeReduxProvider`](#fetchyereduxprovider) and [`makeServerFetchye`](#makeserverfetchye). Please bear in mind that this can impact modules which are do not use the same configuration. @@ -633,13 +633,13 @@ export default BookList; #### One App SSR -Using `makeOneServerFetchye` from `fetchye-one-app` ensures that the cache will +Using `oneFetchye` from `fetchye-one-app` ensures that the cache will always be configured correctly. ```jsx import React from 'react'; import { useFetchye } from 'fetchye'; -import { makeOneServerFetchye } from 'fetchye-one-app'; +import { oneFetchye } from 'fetchye-one-app'; const BookList = () => { const { isLoading, data } = useFetchye('http://example.com/api/books/'); @@ -654,19 +654,14 @@ const BookList = () => { }; BookList.holocron = { - loadModuleData: async ({ store: { dispatch, getState }, fetchClient }) => { + loadModuleData: async ({ store: { dispatch } }) => { if (global.BROWSER) { return; } - const fetchye = makeOneServerFetchye({ - // Redux store - store: { dispatch, getState }, - fetchClient, - }); - // async/await fetchye has same arguments as useFetchye + // oneFetchye has same arguments as useFetchye // dispatches events into the server side Redux store - await fetchye('http://example.com/api/books/'); + await dispatch(oneFetchye('http://example.com/api/books/')); }, }; @@ -795,12 +790,16 @@ const ParentComponent = ({ children }) => ( * [`useFetchye`](#usefetchye) * [`makeServerFetchye`](#makeserverfetchye) +* [`makeOneServerFetchye`](#makeoneserverfetchye) (deprecated) +* [`oneFetchye`](#oneFetchye) * [Providers](#providers) * [`FetchyeProvider`](#fetchyeprovider) * [`FetchyeReduxProvider`](#fetchyereduxprovider) + * [`OneFetchyeProvider`](#oneFetchyeProvider) * [Caches](#caches) * [`SimpleCache`](#simplecache) * [`ImmutableCache`](#immutablecache) + * [`OneCache`](#onecache) * [Actions](#actions) * [`IS_LOADING`](#is_loading) * [`SET_DATA`](#set_data) @@ -885,6 +884,8 @@ const { data, error } = await fetchye(key, options, fetcher); ### `makeOneServerFetchye` +DEPRECATED: You should use `dispatch(oneFetchye(key, options, fetcher))` (see docs below) in place of `makeOneServerFetchye` + A factory function used to generate an async/await fetchye function used for making One App server-side API calls. **Shape** @@ -895,13 +896,13 @@ const fetchye = makeOneServerFetchye({ store, fetchClient }); const { data, error } = await fetchye(key, options, fetcher); ``` -**`makeServerFetchye` Arguments** +**`makeOneServerFetchye` Arguments** | name | type | required | description | |---|---|---|---| | `cache` | `Cache` | `false` | *Defaults to OneCache* Fetchye `Cache` object. | | `fetchClient` | `ES6Fetch` | `true` | A [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) compatible function. | -| `store` | `Store` | `true` | A [Redux Store](https://redux.js.org/api/store) +| `store` | `Store` | `true` | A [Redux Store](https://redux.js.org/api/store) | **`fetchye` Arguments** @@ -919,6 +920,34 @@ const { data, error } = await fetchye(key, options, fetcher); | `error?` | `Object` | An object containing an error if present. *Defaults to an `Error` object with a thrown `fetch` error. This is not for API errors (e.g. Status 500 or 400). See `data` for that* | +### oneFetchye + +Call fetchye in an imperative context, such as in One App's loadModuleData, in a Redux Thunk, or in an useEffect. + +**Shape** + +``` +const { data, error } = await dispatch(onefetchye(key, options, fetcher)); +``` + +**`onefetchye` Arguments** + +| name | type | required | description | +|-----------|------------------------------------------------------------------------------------------------------|------------|---------------------------------------------------------------------------------------------------------------------------------------------------| +| `key` | `String` or `() => String` | `true` | A string or function returning a string that factors into cache key creation. *Defaults to URL compatible string*. | +| `options` | `ES6FetchOptions` | `false` | Options to pass through to [ES6 Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). | +| `fetcher` | `async (fetchClient: Fetch, key: String, options: Options) => ({ payload: Object, error?: Object })` | `false` | The async function that calls `fetchClient` by key and options. Returns a `payload` with outcome of `fetchClient` and an optional `error` object. | + +**`onefetchye` Returns** + +A promise resolving to an object with the below keys: + +| name | type | description | +|----------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `data` | `Object` | A result of a `fetchClient` query. *Defaults to returning `{ status, body, ok, headers }` from `fetchClient` response* | +| `error?` | `Object` | An object containing an error if present. *Defaults to an `Error` object with a thrown `fetch` error. This is not for API errors (e.g. Status 500 or 400). See `data` for that* | + + ### Providers A Provider creates a React Context to connect all the `useFetchye` Hooks into a centrally stored cache. diff --git a/packages/fetchye-one-app/__tests__/oneFetchye.spec.js b/packages/fetchye-one-app/__tests__/oneFetchye.spec.js new file mode 100644 index 0000000..7693910 --- /dev/null +++ b/packages/fetchye-one-app/__tests__/oneFetchye.spec.js @@ -0,0 +1,33 @@ +import oneFetchye from '../src/oneFetchye'; + +const mockOneCacheSymbol = Symbol('oneCache'); +jest.mock('../src/OneCache', () => jest.fn(() => mockOneCacheSymbol)); +jest.mock('fetchye', () => ({ + makeServerFetchye: jest.fn((...makeFetchyeArgs) => jest.fn((...fetcheArgs) => Promise.resolve( + { makeFetchyeArgs, fetcheArgs } + ))), +})); +describe('oneFetchye', () => { + it('should return a one-app-thunk that calls fetchye', async () => { + expect.assertions(1); + const fetchyeParams = [Symbol('fetchyeArgs 1'), Symbol('fetchyeArgs 2')]; + const fetchyeThunk = oneFetchye(...fetchyeParams); + const thunkParams = [Symbol('dispatch'), Symbol('getState'), Symbol('fetchClient')]; + const response = await fetchyeThunk( + thunkParams[0], thunkParams[1], { fetchClient: thunkParams[2] } + ); + expect(response).toStrictEqual({ + fetcheArgs: fetchyeParams, + makeFetchyeArgs: [ + { + cache: mockOneCacheSymbol, + fetchClient: thunkParams[2], + store: { + dispatch: thunkParams[0], + getState: thunkParams[1], + }, + }, + ], + }); + }); +}); diff --git a/packages/fetchye-one-app/src/index.js b/packages/fetchye-one-app/src/index.js index e40b1cf..cf15f74 100644 --- a/packages/fetchye-one-app/src/index.js +++ b/packages/fetchye-one-app/src/index.js @@ -17,3 +17,4 @@ export { makeOneServerFetchye } from './makeOneServerFetchye'; export OneCache, { oneCacheSelector } from './OneCache'; export OneFetchyeProvider from './OneFetchyeProvider'; +export oneFetchye from './oneFetchye'; diff --git a/packages/fetchye-one-app/src/oneFetchye.js b/packages/fetchye-one-app/src/oneFetchye.js new file mode 100644 index 0000000..8fdc484 --- /dev/null +++ b/packages/fetchye-one-app/src/oneFetchye.js @@ -0,0 +1,13 @@ +import { makeServerFetchye } from 'fetchye'; +import OneCache from './OneCache'; + +const oneFetchye = (...fetchyeArgs) => async (dispatch, getState, { fetchClient }) => { + const fetchye = makeServerFetchye({ + store: { getState, dispatch }, + fetchClient, + cache: OneCache(), + }); + return fetchye(...fetchyeArgs); +}; + +export default oneFetchye;