{"id":21214398,"url":"https://github.com/oberonamsterdam/react-api-data","last_synced_at":"2025-07-10T10:30:21.310Z","repository":{"id":26896022,"uuid":"110534589","full_name":"oberonamsterdam/react-api-data","owner":"oberonamsterdam","description":"Automate calling external APIs and handling response data for React apps.","archived":false,"fork":false,"pushed_at":"2023-02-04T06:30:08.000Z","size":2706,"stargazers_count":21,"open_issues_count":5,"forks_count":7,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-04-25T00:01:49.501Z","etag":null,"topics":["react","redux"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oberonamsterdam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-11-13T10:34:07.000Z","updated_at":"2022-04-10T07:03:07.000Z","dependencies_parsed_at":"2023-02-18T23:30:28.050Z","dependency_job_id":null,"html_url":"https://github.com/oberonamsterdam/react-api-data","commit_stats":null,"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oberonamsterdam%2Freact-api-data","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oberonamsterdam%2Freact-api-data/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oberonamsterdam%2Freact-api-data/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oberonamsterdam%2Freact-api-data/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oberonamsterdam","download_url":"https://codeload.github.com/oberonamsterdam/react-api-data/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225632181,"owners_count":17499742,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react","redux"],"created_at":"2024-11-20T21:27:43.763Z","updated_at":"2024-11-20T21:27:44.482Z","avatar_url":"https://github.com/oberonamsterdam.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-api-data\n\n[![npm](https://img.shields.io/npm/v/react-api-data.svg)](https://www.npmjs.com/package/react-api-data)\n[![Build Status](https://github.com/oberonamsterdam/react-api-data/workflows/Build/badge.svg?branch=master)](https://github.com/oberonamsterdam/react-api-data/actions?query=workflow%3ABuild+branch%3Amaster)\n\nAutomate calling external APIs and handling response data. Supports any API with JSON responses. Uses Fetch for\nperforming API requests, normalizr for handling response data and redux for storing data.\n\n## Installation\n\n`npm install react-api-data`\n\nor\n\n`yarn add react-api-data`\n\nMake sure _fetch_ is available globally, polyfill it if needed to support older environments.\n\n## Install dependencies\n\nReact-api-data requires the installation of the peer-dependencies react-redux, redux-thunk and normalizr. \nThese can be installed with the following command:\n\n`npm install redux react-redux redux-thunk normalizr`\n\nor\n\n`yarn add redux react-redux redux-thunk normalizr`\n\n## API\n\n[API specification](api.md)\n\n## Quick usage\n\n### Config\n\n```js\nimport { schema } from 'normalizr';\nimport { createStore, applyMiddleware, combineReducers } from 'redux';\nimport { configure, reducer } from 'react-api-data';\nimport thunk from 'redux-thunk';\n\n// optionally define normalizr response schemas\n\nconst authorSchema = new schema.Entity('Author');\nconst articleSchema = new schema.Entity('Article', {\n    author: authorSchema\n});\n\n// define api endpoints\n\nconst endpointConfig = {\n    getArticle: {\n        url: 'http://www.mocky.io/v2/5a0c203e320000772de9664c?:articleId/:userId',\n        method: 'GET',\n        responseSchema: articleSchema\n    },\n    saveArticle: {\n        url: 'http://www.mocky.io/v2/5a0c203e320000772de9664c?:articleId',\n        method: 'POST',\n        afterSuccess: ({ dispatch, request, getState }) =\u003e {\n            // After successful post, invalidate the cache of the getArticle call, so it gets re-triggered.\n            dispatch(invalidateRequest('getArticle', {articleId: request.params.articleId, userId: getState().userId})); \n        }\n    }\n};\n\n// Configure store and dispatch config before you render components\n\nconst store = createStore(combineReducers({apiData: reducer}), applyMiddleware(thunk));\nstore.dispatch(configure({}, endpointConfig));\n```\n\n### Bind API data to your component\n\n```js\nimport React from 'react';\nimport { useApiData } from 'react-api-data';\n\nconst Article = (props) =\u003e {\n    const article = useApiData('getArticle', { id: props.articleId });\n    return (\n        \u003c\u003e\n            {article.request.networkStatus === 'success' \u0026\u0026\n                \u003cdiv\u003e\n                    \u003ch1\u003e{article.data.title}\u003c/h1\u003e\n                    \u003cp\u003e{article.data.body}\u003c/p\u003e\n                \u003c/div\u003e\n            }\n        \u003c/\u003e\n    );\n}\n\n```\n\n### Optionally use React Suspense\n\nReact-api-data supports [React Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html). Suspense can be enabled globally, per endpoint or per Hook/HOC. It is also possible to override the suspense setting for an endpoint or Hook/HOC.\n\n```js\nimport React from 'react';\nimport { useApiData } from 'react-api-data';\n\nconst Article = (props) =\u003e {\n    const article = useApiData('getArticle', { id: props.articleId }, { enableSuspense: true });\n    return (\n        \u003c\u003e\n            {article.request.networkStatus === 'success' \u0026\u0026\n                \u003cdiv\u003e\n                    \u003ch1\u003e{article.data.title}\u003c/h1\u003e\n                    \u003cp\u003e{article.data.body}\u003c/p\u003e\n                \u003c/div\u003e\n            }\n        \u003c/\u003e\n    );\n};\n\nconst ArticleList = (props) =\u003e {\n    return (\n        \u003c\u003e\n            \u003cSuspense fallback={\u003cArticleListLoading/\u003e}\u003e\n                {props.articles.map(article =\u003e \u003cArticle articleId={article.id}/\u003e}\n            \u003c/Suspense\u003e\n        \u003c/\u003e\n    );\n}\n\n```\n\n### Post data from your component\n\n```js\nimport React, { useState } from 'react';\nimport { useApiData } from 'react-api-data';\n\nconst PostComment = props =\u003e {\n    const [comment, setComment] = useState('');\n    const postComment = useApiData('postComment', undefined, {\n        // If a certain call requires a different config from what you've defined in the api endpoint config, you can pass config overrides as the third argument.\n        autoTrigger: false,\n    });\n    const { networkStatus } = postComment.request;\n    const onSubmit = () =\u003e {\n        postComment.perform({ id: props.articleId }, { comment });\n    };\n    return (\n        \u003c\u003e\n            {networkStatus === 'ready' \u0026\u0026 (\n                \u003cdiv\u003e\n                    \u003cinput\n                        onChange={event =\u003e setComment(event.target.value)}\n                        placeholder=\"Add a comment...\"\n                    /\u003e\n                    \u003cbutton onClick={onSubmit}\u003eSubmit\u003c/button\u003e\n                \u003c/div\u003e\n            )}\n            {networkStatus === 'loading' \u0026\u0026 \u003cdiv\u003eSubmitting...\u003c/div\u003e}\n            {networkStatus === 'failed' \u0026\u0026 (\n                \u003cdiv\u003e\n                    Something went wrong.\n                    \u003cbutton onClick={onSubmit}\u003eTry again\u003c/button\u003e\n                \u003c/div\u003e\n            )}\n            {networkStatus === 'success' \u0026\u0026 \u003cdiv\u003eSubmitted!\u003c/div\u003e}\n        \u003c/\u003e\n    );\n};\n```\n\n# The gist\n\nCalling external API endpoints and storing response data in your [redux](https://redux.js.org) state can create\nbloat in your code when you have multiple endpoints, especially in [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete)\napplications. This package is the result of eliminating repetitive code around API calls and centralizing the concerns of\nfetching and storing API data into one single package. It provides an easy to use interface that aims to minimize the\namount of code needed to use data from external APIs, while maintaining maximum flexibility to support any non-standard\nAPI. The idea is that you can just bind data from a given API endpoint to your component, react-api-data takes care of\nfetching the data if needed, and binding the data to your component.\n\n# Examples\n\n## Caching API responses\n\nResponses from successful API calls will be kept in memory so the same call won't be re-triggered a second time. This is especially useful when using *withApiData* for the same endpoint on multiple components.\nYou can set a *cacheDuration* to specify how long the response is considered valid, or to disable the caching entirely.\n\n```js\nexport default {\n    getArticle: {\n        url: 'http://www.mocky.io/v2/5a0c203e320000772de9664c?:articleId/:userId',\n        method: 'GET',\n        cacheDuration: 60000, // 1 minute\n    },\n    getComments: {\n        url: 'http://www.mocky.io/v2/5a0c203e320000772de9664c?:articleId',\n        method: 'GET',\n        cacheDuration: 0, // no caching, use with caution. Preferably set to a low value to prevent multiple simultaneous calls.\n    },\n    getPosts: {\n        url: 'http://www.mocky.io/v2/5a0c203e320000772de9664c?:articleId',\n        method: 'GET'\n        // Infinite caching\n    },\n}\n```\n\n## Manually clearing cache from your component\n\n```js\nimport { useApiData } from 'react-api-data';\n\nconst Articles = props =\u003e {\n    const getArticles = useApiData('getArticles');\n    return (\n        \u003c\u003e\n            {/* ... */}\n            \u003cbutton onClick={getArticles.invalidateCache}\u003eRefresh\u003c/button\u003e\n        \u003c/\u003e\n    );\n}\n\n```\n\n## Manually clearing cache using useActions\n\nUsing the useActions api to invalidate the cache of a specific endpoint.\n\n```js\nimport { useActions} from 'react-api-data';\n\nconst Articles = props =\u003e {\n    const actions = useActions();\n    return (\n        \u003c\u003e\n            {/* ... */}\n            \u003cbutton onClick={() =\u003e actions.invalidateCache('getArticle', {id: '1234'})}\u003eRefresh\u003c/button\u003e\n        \u003c/\u003e\n    );\n}\n\n```\n\n## Removing api data from the store\n\n```js\nimport { useActions} from 'react-api-data';\n\nconst LogoutComponent = props =\u003e {\n    const actions = useActions();\n    return (\n        \u003c\u003e\n            {/* ... */}\n            \u003cbutton onClick={() =\u003e actions.purgeAll()}\u003eLogout\u003c/button\u003e\n        \u003c/\u003e\n    );\n}\n```\n\n## Including Cookies in your Request\n\n```js\nexport const globalConfig = {\n    setRequestProperties: (defaultProperties) =\u003e ({\n        ...defaultProperties,\n        credentials: 'include',\n    })\n};\n```\n\n## Using default parameters\n\nThere might be situations where default parameters are needed, for example when using a language in a URL. These default parameters can be set with the `defaultParams` object in your [endpointConfig](https://github.com/oberonamsterdam/react-api-data/blob/master/api.md#endpointconfig):\n\n```js\nconst endpointConfig = {\n    getData: {\n        url: `${BASE_URL}/:language/getData.json`,\n        method: 'GET',\n        defaultParams: {\n            language: 'en',\n        },\n    },\n};\n```\n\nYou can set default values for multiple parameters or only part of the parameters. Their value should be either a `string` or a `number`.\n\nPlease note that these `defaultParams` will be overwritten if they are explicitly set in the request paramaters.\n\n## Uploading a file\n\n[See file Upload examples](./example.file-upload.md)\n\n## Make multiple requests to the same endpoint at once\n\n```js\nconst connectApiData = withApiData({\n    items: 'getItemsInList'\n}, (ownProps, state) =\u003e ({\n    items: [{listId: 1}, {listId: 2}, {listId: 3}]\n}));\n\nconst ItemsList = (props) =\u003e {\n    if (props.items.every(item =\u003e item.request.networkStatus === 'success')) {\n        return (\n            \u003cul\u003e\n                {props.items.map(item =\u003e (\u003cli\u003e{item.data.title}\u003c/li\u003e))}\n            \u003c/ul\u003e\n        );\n    }\n    return \u003cp\u003eLoading...\u003c/p\u003e;\n}\n\nexport default connectApiData(ItemsList);\n```\n\n## Configure with Redux-persist\n\n```js\n    // Use the callback of redux-persist to dispatch the afterRehydrate function.\n    // This will make sure all loading states are properly reset.\n    const persistor = persistStore(store, {}, () =\u003e store.dispatch(afterRehydrate()));\n    store.dispatch(configure({}, endpointConfig));\n    return {\n        store,\n        persistor,\n    };\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foberonamsterdam%2Freact-api-data","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foberonamsterdam%2Freact-api-data","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foberonamsterdam%2Freact-api-data/lists"}