{"id":19806444,"url":"https://github.com/ory/redux-saga-fetch","last_synced_at":"2025-05-01T07:30:51.295Z","repository":{"id":57316383,"uuid":"81662895","full_name":"ory/redux-saga-fetch","owner":"ory","description":"A simple wrapper that reduces boilerplate code when using redux-saga in combination with async backend calls.","archived":false,"fork":false,"pushed_at":"2025-03-12T16:26:52.000Z","size":236,"stargazers_count":17,"open_issues_count":1,"forks_count":3,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-20T18:20:51.780Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ory.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-02-11T15:48:29.000Z","updated_at":"2025-04-09T10:11:40.000Z","dependencies_parsed_at":"2022-08-25T20:40:33.905Z","dependency_job_id":null,"html_url":"https://github.com/ory/redux-saga-fetch","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fredux-saga-fetch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fredux-saga-fetch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fredux-saga-fetch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fredux-saga-fetch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ory","download_url":"https://codeload.github.com/ory/redux-saga-fetch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250746448,"owners_count":21480405,"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":[],"created_at":"2024-11-12T09:07:35.578Z","updated_at":"2025-05-01T07:30:51.275Z","avatar_url":"https://github.com/ory.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# redux-saga-fetch\n\n[![Build Status](https://travis-ci.org/ory/redux-saga-fetch.svg?branch=master)](https://travis-ci.org/ory/redux-saga-fetch)\n[![Coverage Status](https://coveralls.io/repos/github/ory/redux-saga-fetch/badge.svg?branch=master)](https://coveralls.io/github/ory/redux-saga-fetch?branch=master)\n\n`ory-redux-saga-fetch` is a simple wrapper that reduces boilerplate code when using `redux-saga` in combination with\nasync backend calls.\n\n## Installation\n\n```\nnpm i --save ory-redux-saga-fetch\n```\n\n## API\n\n```jsx\nimport { applyMiddleware, combineReducers, createStore } from 'redux'\nimport createSagaMiddleware from 'redux-saga'\n\nimport {\n  createRequestAction,\n  createSagaFetcher,\n  isFetchFailure,\n  isFetching,\n  isFetchSuccess,\n  selectPayload,\n  selectErrorPayload\n} from 'ory-redux-saga-fetch'\n\n// Some exemplary functions that call a backend and return a promise.\n// For more information on the fetch API, go here: https://github.com/bitinn/node-fetch\nconst getUsersFromAPI = () =\u003e fetch('http://myapi.com/users').then(res =\u003e res.JSON())\nconst getArticleFromAPI = (id) =\u003e fetch('http://myapi.com/articles/' + id).then(res =\u003e res.JSON())\nconst createArticleAtAPI = (article) =\u003e fetch('http://myapi.com/articles', { method: 'POST', body: JSON.stringify(article) }).then(res =\u003e res.JSON())\n\n// Configuring our fetcher\nconst sagaFetcher = createSagaFetcher({\n  users: {\n    // Fetch is executed when the according action is triggered. Fetch expects a function that returns a Promise.\n    fetcher: getUsersFromAPI\n  },\n  article: {\n    // The action payload (see below) will be passed as the first argument.\n    fetcher: (id) =\u003e getUsersFromAPI(id),\n    // If any key of the group is fetching (in this case 'article' and 'createArticle') and\n    // the other one is requested, the first one has to finish first before the second one gets fetched.\n    group: 'article'\n  },\n  createArticle: {\n    // This works with POST/PUT/DELETE/... methods as well\n    fetcher: (payload) =\u003e createArticleAtAPI(payload),\n    group: 'article'\n  },\n  contactEditor: {\n    // supposed this fetcher needs to get the email address of the editor out of the store\n    fetcher: (text, address) =\u003e writeEmail({ to: address, subject: 'send over redux-saga-fetch', text }),\n    // selector is a regular redux selector taking the state and returning a partial state of choice\n    selector: (state) =\u003e state.contacts.editor.emailAddress\n})\n\n// We need to wrap the root reducer in order to get sagaFetcher to work.\nconst rootReducer = combineReducers(\n  sagaFetcher.wrapRootReducer({\n    myOtherReducer1: (action, state) =\u003e ({ /*...*/ })\n    myOtherReducer2: (action, state) =\u003e ({ /*...*/ })\n  })\n)\n\n// This is regular redux stuff\nconst initialState = {}\nconst sagaMiddleware = createSagaMiddleware()\nconst store = createStore(\n  rootReducer,\n  initialState,\n  applyMiddleware(sagaMiddleware)\n)\n\n// We need to register the saga watchers of reduxSagaFetch\nsagaMiddleware.run(sagaFetcher.createRootSaga())\n\n\n// Now we're done, let's dispatch some actions!\ncreateRequestAction('users')()\ncreateRequestAction('article')(1234)\ncreateRequestAction('createArticle')({ id: 12345, title: 'foo' })\n\n// Now, the saga watchers will execute the API calls. In the meanwhile, you can check the status of each request using\nisFetching('users')(store.getState()) // if true, the API call has not finished yet.\nisFetchSuccess('users')(store.getState()) // if true, the API call resultet in Promise.resolve()\nisFetchError('users')(store.getState()) // if true, the API call resultet in Promise.reject()\n\n// Let's assume the API call has finished with an ok status code, and we want to see the result.\nconst users = selectPayload('users')(store.getState())\n\n// Let's assume the API call has finished with an error (e.g. network or status code != 2xx), use this method to retrieve\n// the error:\nconst error = selectErrorPayload('users')(store.getState())\n```\n\nAssuming you are using redux together with React, you could write your connector like this:\n\n```jsx\nimport React from 'react'\nimport { connect } from 'react-redux'\nimport {\n  createRequestAction,\n  createSagaFetcher,\n  isFetchFailure,\n  isFetching,\n  isFetchSuccess,\n  selectPayload\n} from 'ory-redux-saga-fetch'\n\nconst Component = ({ getUsers, users, isFetchingUsers }) =\u003e (\n  \u003cdiv\u003e\n    \u003cbutton onClick={getUsers()} /\u003e\n    {isFetchingUsers ? 'still fetching...' : users}\n  \u003c/div\u003e\n)\n\n\nconst mapStateToProps = (state) =\u003e ({\n  isFetchingUsers: isFetching('users')(state)\n  users: selectPayload('users')(state)\n}\n\nconst mapDispatchToProps = (dispatch) =\u003e ({\n  getUsers: createRequestAction('users')\n})\n\nexport default connect(mapStateToProps, mapDispatchToProps)(Component)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fory%2Fredux-saga-fetch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fory%2Fredux-saga-fetch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fory%2Fredux-saga-fetch/lists"}