{"id":22466436,"url":"https://github.com/coreh/restore","last_synced_at":"2026-04-28T11:35:20.075Z","repository":{"id":57103972,"uuid":"128504096","full_name":"coreh/RESTore","owner":"coreh","description":"RESTful Data Store","archived":false,"fork":false,"pushed_at":"2018-04-30T00:33:20.000Z","size":335,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-17T21:45:50.390Z","etag":null,"topics":["datastore","fetch","javascript","rest","restful","state","unidirectional-data-flow"],"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/coreh.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","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":"2018-04-07T06:51:49.000Z","updated_at":"2018-05-24T00:51:39.000Z","dependencies_parsed_at":"2022-08-20T20:40:34.663Z","dependency_job_id":null,"html_url":"https://github.com/coreh/RESTore","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coreh%2FRESTore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coreh%2FRESTore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coreh%2FRESTore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coreh%2FRESTore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coreh","download_url":"https://codeload.github.com/coreh/RESTore/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245868331,"owners_count":20685609,"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":["datastore","fetch","javascript","rest","restful","state","unidirectional-data-flow"],"created_at":"2024-12-06T10:12:15.249Z","updated_at":"2026-04-28T11:35:20.011Z","avatar_url":"https://github.com/coreh.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RESTore\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/coreh/RESTore/raw/master/logo.png\" width=\"256\" height=\"256\"\u003e\u003cbr\u003e\n\u003cstrong\u003eRESTful Data Store\u003c/strong\u003e\u003cbr\u003e\u003cbr\u003e\n\u003ca href=\"https://www.npmjs.com/package/@coreh/restore\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/@coreh/restore.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/npm/l/@coreh/restore.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://travis-ci.org/coreh/RESTore/\"\u003e\u003cimg src=\"https://img.shields.io/travis/coreh/RESTore.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://coveralls.io/github/coreh/RESTore\"\u003e\u003cimg src=\"https://img.shields.io/coveralls/github/coreh/RESTore.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://david-dm.org/coreh/RESTore\"\u003e\u003cimg src=\"https://img.shields.io/david/coreh/RESTore.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Introduction\n\n**RESTore** combines the unidirectional data flow model found in libraries like [Redux](https://redux.js.org) with familiar HTTP semantics.\n\nIts design is informed by field experience with mantaining large Redux applications, with the key realization that despite the fact that almost any useful Redux application will end up interfacing with a REST API, it is currently not very ergonomic to do so.\n\nRESTore's API is fully asynchronous, and meant to go hand-in-hand with the new suspending strategy found in React.\n\n### Development Status\n\nThis library is still on its early days, and is certainly not suitable for production. Expect significant changes as the API gets polished.\n\n### Key inspirations\n\nRESTore is inspired by the following APIs/concepts:\n\n- Redux\n- React Suspense\n- REST\n- Fetch API\n- Express/Connect/Koa\n- Service Workers\n\n## Conceptual Comparison (Redux)\n\n| Redux          | RESTore                                                  |\n|----------------|----------------------------------------------------------|\n| Store          | Store                                                    |\n| Action         | Request                                                  |\n| Reducer        | Handler                                                  |\n| `.dispatch()`  | `.fetch()`                                               |\n| Action Type    | HTTP Verb (`GET`, `POST`, `PUT`, ...)                    |\n| Action Creator | Convenience Methods (`.get()`, `.post()`, `.put()`, ...) |\n| Selector       | Path                                                     |\n| `.subscribe()` | `.subscribe()`                                           |\n\n## Examples\n\n### Store Definition\n\n```js\nimport RESTore from '@coreh/restore';\n\nconst store = new RESTore();\n\nstore.use('/users/:id', async function ({ method, body, path }, next) {\n    switch (method) {\n        case 'PATCH':\n            const stored = this.stored(path);\n            if (stored === undefined) {\n                throw new Error('User does not exist');\n            }\n            return {\n                ...stored,\n                ...body,\n            };\n        default:\n            return next();\n    }\n});\n\nstore.use('/users', async function ({ method, body, path }, next) {\n    switch (method) {\n        case 'POST':\n            return {\n                [RESTore.Path]: ['users', body.username], // Same as `/users/${body.username}`\n                ...body,\n            };\n        default:\n            return next();\n    }\n});\n```\n\n### Store Usage\n\n```js\nawait store.post('/users', {\n    username: 'coreh',\n    likes: ['Chocolate', 'Coffee'],\n});\n\nawait store.patch('/users/coreh', { singing: true });\n\nconsole.log(await store.get('/users/coreh'));\n// { username: 'coreh',\n//   likes: ['Chocolate', 'Coffee'],\n//   singing: true }\n```\n\n### Mounting existing REST API endpoints\n\n```js\nimport endpoint from '@coreh/restore/endpoint';\n\n// Declaration\nstore.use(endpoint('https://api.example.com/'));\n\n// Usage\nstore.get(['flights', airport])\n```\n\n### Integrating with React \"Suspense\"\n\n```jsx\nconst Weather = (props) =\u003e {\n    // .take() -\u003e .get(), but will throw promise if not fetched\n    const weather = store.take(['weather', props.location]);\n    return (\n        \u003cdiv\u003e\n            \u003cp\u003eTemperature: {weather.temperature}\u003c/p\u003e\n            \u003cp\u003eHumidity: {weather.humidity}\u003c/p\u003e\n        \u003c/div\u003e\n    )\n}\n```\n\n### Yield multiple resources (Async Generators)\n\nTODO\n\n### Caching\n\nTODO\n\n### Optimistic Loading / Progress Reporting\n\nTODO\n\n## License\n\nMIT, see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoreh%2Frestore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoreh%2Frestore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoreh%2Frestore/lists"}