{"id":13496120,"url":"https://github.com/reactive/data-client","last_synced_at":"2026-04-02T00:12:37.124Z","repository":{"id":38895424,"uuid":"170797156","full_name":"reactive/data-client","owner":"reactive","description":"Async State Management without the Management. REST, GraphQL, SSE, Websockets","archived":false,"fork":false,"pushed_at":"2025-05-04T01:15:15.000Z","size":344734,"stargazers_count":1991,"open_issues_count":10,"forks_count":96,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-05-08T08:41:16.035Z","etag":null,"topics":["expo","fetch","hooks","normalized","normalizr","react","react-native","reactive-programming","rest","sse-client","state-management","suspense","typescript"],"latest_commit_sha":null,"homepage":"https://dataclient.io","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/reactive.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["ntucker"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2019-02-15T03:37:05.000Z","updated_at":"2025-05-06T13:07:45.000Z","dependencies_parsed_at":"2023-08-28T06:23:51.626Z","dependency_job_id":"37ae0b72-6259-4ba9-9dfc-1c5867969a6f","html_url":"https://github.com/reactive/data-client","commit_stats":{"total_commits":4304,"total_committers":38,"mean_commits":"113.26315789473684","dds":"0.39335501858736055","last_synced_commit":"f6d11e960928abd71591d8c6fb2b1b5a8bf0e1ae"},"previous_names":["coinbase/rest-hooks","data-client/data-client","reactive/data-client","data-client/rest-hooks"],"tags_count":1712,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactive%2Fdata-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactive%2Fdata-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactive%2Fdata-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactive%2Fdata-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reactive","download_url":"https://codeload.github.com/reactive/data-client/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253990470,"owners_count":21995774,"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":["expo","fetch","hooks","normalized","normalizr","react","react-native","reactive-programming","rest","sse-client","state-management","suspense","typescript"],"created_at":"2024-07-31T19:01:42.572Z","updated_at":"2026-04-02T00:12:37.109Z","avatar_url":"https://github.com/reactive.png","language":"TypeScript","readme":"\u003cdiv align=\"center\"\u003e\n\u003ca href=\"https://dataclient.io\" target=\"_blank\" rel=\"noopener\"\u003e\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/reactive/data-client/raw/master/website/static/img/client_logo_and_text-border--dark.svg?sanitize=true\"\u003e\n  \u003cimg alt=\"Reactive Data Client\" src=\"https://github.com/reactive/data-client/raw/master/website/static/img/client_logo_and_text-border--light.svg?sanitize=true\"\u003e\n\u003c/picture\u003e\n\u003c/a\u003e\n\nThe scalable way to build applications with [dynamic data](https://dataclient.io/docs/getting-started/mutations).\n\n[Declarative resouce definitons](https://dataclient.io/docs/getting-started/resource) for [REST](https://dataclient.io/rest), [GraphQL](https://dataclient.io/graphql), [Websockets+SSE](https://dataclient.io/docs/concepts/managers#data-stream) and [more](https://dataclient.io/rest/api/Endpoint)\n\u003cbr/\u003e[Performant rendering](https://dataclient.io/docs/getting-started/data-dependency) in [React](https://react.dev/), [NextJS](https://nextjs.org/), [React Native](https://reactnative.dev/), [Expo](https://expo.dev/), [Vue](https://vuejs.org/)\n\nSchema driven. Zero updater functions.\n\n[![CircleCI](https://circleci.com/gh/reactive/data-client/tree/master.svg?style=shield)](https://circleci.com/gh/reactive/data-client)\n[![Coverage Status](https://img.shields.io/codecov/c/gh/reactive/data-client/master.svg?style=flat-square)](https://app.codecov.io/gh/reactive/data-client?branch=master)\n[![Percentage of issues still open](https://isitmaintained.com/badge/open/reactive/data-client.svg)](https://github.com/reactive/data-client/issues 'Percentage of issues still open')\n[![bundle size](https://img.shields.io/bundlephobia/minzip/@data-client/react?style=flat-square)](https://bundlephobia.com/result?p=@data-client/react)\n[![npm version](https://img.shields.io/npm/v/@data-client/react.svg?style=flat-square)](https://www.npmjs.com/package/@data-client/react)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)\n[![Agent Skills](https://img.shields.io/badge/Agent_Skills-cc785c?style=flat-square\u0026logo=claude\u0026logoColor=white)](https://skills.sh/reactive/data-client)\n[![Chat](https://img.shields.io/discord/768254430381735967.svg?style=flat-square\u0026colorB=758ED3)](https://discord.gg/35nb8Mz)\n\n**[📖Read The Docs](https://dataclient.io/docs)** \u0026nbsp;|\u0026nbsp; [🏁Getting Started](https://dataclient.io/docs/getting-started/installation) \u0026nbsp;|\u0026nbsp; [🤖Agent Skills](https://skills.sh/reactive/data-client)\u003cbr/\u003e🎮 Demos: \u0026nbsp;\n[Todo](https://stackblitz.com/github/reactive/data-client/tree/master/examples/todo-app?file=src%2Fpages%2FHome%2FTodoList.tsx) \u0026nbsp;|\u0026nbsp;\n[Github Social](https://stackblitz.com/github/reactive/data-client/tree/master/examples/github-app?file=src%2Fpages%2FIssueList.tsx) \u0026nbsp;|\u0026nbsp;\n[NextJS SSR](https://stackblitz.com/github/reactive/data-client/tree/master/examples/nextjs?file=components%2Ftodo%2FTodoList.tsx) \u0026nbsp;|\u0026nbsp;\n[Websockets+SSR](https://stackblitz.com/github/reactive/coin-app/tree/master?file=src%2Fresources%2FStreamManager.ts,src%2Fapp%2FCurrencyList.tsx)\n\n\u003c/div\u003e\n\n## Installation\n\n```bash\nnpm install --save @data-client/react @data-client/rest @data-client/test\n```\n\nFor more details, see [the Installation docs page](https://dataclient.io/docs/getting-started/installation).\n\n### Skills\n\n```bash\nnpx skills add reactive/data-client\n```\n\nThen run [skill](https://agentskills.io) \"data-client-setup\"\n\n## Usage\n\n### Simple [TypeScript definition](https://dataclient.io/rest/api/Entity)\n\n```typescript\nclass User extends Entity {\n  id = '';\n  username = '';\n}\n\nclass Article extends Entity {\n  id = '';\n  title = '';\n  body = '';\n  author = User.fromJS();\n  createdAt = Temporal.Instant.fromEpochMilliseconds(0);\n\n  static schema = {\n    author: User,\n    createdAt: Temporal.Instant.from,\n  };\n}\n```\n\n### Create [collection of API Endpoints](https://dataclient.io/docs/getting-started/resource)\n\n```typescript\nconst UserResource = resource({\n  path: '/users/:id',\n  schema: User,\n  optimistic: true,\n});\n\nconst ArticleResource = resource({\n  path: '/articles/:id',\n  schema: Article,\n  searchParams: {} as { author?: string },\n  optimistic: true,\n  paginationField: 'cursor',\n});\n```\n\n### One line [data binding](https://dataclient.io/docs/getting-started/data-dependency)\n\n```tsx\nconst article = useSuspense(ArticleResource.get, { id });\nreturn (\n  \u003carticle\u003e\n    \u003ch2\u003e\n      {article.title} by {article.author.username}\n    \u003c/h2\u003e\n    \u003cp\u003e{article.body}\u003c/p\u003e\n  \u003c/article\u003e\n);\n```\n\n### [Reactive Mutations](https://dataclient.io/docs/getting-started/mutations)\n\n```tsx\nconst ctrl = useController();\nreturn (\n  \u003c\u003e\n    \u003cCreateArticleForm\n      onSubmit={article =\u003e\n        ctrl.fetch(ArticleResource.getList.push, { id }, article)\n      }\n    /\u003e\n    \u003cProfileForm\n      onSubmit={user =\u003e\n        ctrl.fetch(UserResource.update, { id: article.author.id }, user)\n      }\n    /\u003e\n    \u003cbutton onClick={() =\u003e ctrl.fetch(ArticleResource.delete, { id })}\u003e\n      Delete\n    \u003c/button\u003e\n  \u003c/\u003e\n);\n```\n\n### [Subscriptions](https://dataclient.io/docs/api/useLive)\n\n```tsx\nconst price = useLive(PriceResource.get, { symbol });\nreturn price.value;\n```\n\n### [Type-safe Imperative Actions](https://dataclient.io/docs/api/Controller)\n\n```tsx\nconst ctrl = useController();\nawait ctrl.fetch(ArticleResource.update, { id }, articleData);\nawait ctrl.fetchIfStale(ArticleResource.get, { id });\nctrl.expireAll(ArticleResource.getList);\nctrl.invalidate(ArticleResource.get, { id });\nctrl.invalidateAll(ArticleResource.getList);\nctrl.setResponse(ArticleResource.get, { id }, articleData);\nctrl.set(Article, { id }, articleData);\n```\n\n### [Programmatic queries](https://dataclient.io/rest/api/Query)\n\n```typescript\nconst queryTotalVotes = new Query(\n  new Collection([BlogPost]),\n  posts =\u003e posts.reduce((total, post) =\u003e total + post.votes, 0),\n);\n\nconst totalVotes = useQuery(queryTotalVotes);\nconst totalVotesForUser = useQuery(queryTotalVotes, { userId });\n```\n\n```typescript\nconst groupTodoByUser = new Query(\n  TodoResource.getList.schema,\n  todos =\u003e Object.groupBy(todos, todo =\u003e todo.userId),\n);\nconst todosByUser = useQuery(groupTodoByUser);\n```\n\n### [Powerful Middlewares](https://dataclient.io/docs/concepts/managers)\n\n```ts\nclass LoggingManager implements Manager {\n  middleware: Middleware = controller =\u003e next =\u003e async action =\u003e {\n    console.log('before', action, controller.getState());\n    await next(action);\n    console.log('after', action, controller.getState());\n  };\n\n  cleanup() {}\n}\n```\n\n```ts\nclass TickerStream implements Manager {\n  middleware: Middleware = controller =\u003e {\n    this.handleMsg = msg =\u003e {\n      controller.set(Ticker, { id: msg.id }, msg);\n    };\n    return next =\u003e action =\u003e next(action);\n  };\n\n  init() {\n    this.websocket = new WebSocket('wss://ws-feed.myexchange.com');\n    this.websocket.onmessage = event =\u003e {\n      const msg = JSON.parse(event.data);\n      this.handleMsg(msg);\n    };\n  }\n  cleanup() {\n    this.websocket.close();\n  }\n}\n```\n\n### [Integrated data mocking](https://dataclient.io/docs/api/Fixtures)\n\n```tsx\nconst fixtures = [\n  {\n    endpoint: ArticleResource.getList,\n    args: [{ maxResults: 10 }] as const,\n    response: [\n      {\n        id: '5',\n        title: 'first post',\n        body: 'have a merry christmas',\n        author: { id: '10', username: 'bob' },\n        createdAt: new Date(0).toISOString(),\n      },\n      {\n        id: '532',\n        title: 'second post',\n        body: 'never again',\n        author: { id: '10', username: 'bob' },\n        createdAt: new Date(0).toISOString(),\n      },\n    ],\n  },\n  {\n    endpoint: ArticleResource.update,\n    response: ({ id }, body) =\u003e ({\n      ...body,\n      id,\n    }),\n  },\n];\n\nconst Story = () =\u003e (\n  \u003cMockResolver fixtures={options[result]}\u003e\n    \u003cArticleList maxResults={10} /\u003e\n  \u003c/MockResolver\u003e\n);\n```\n\n### ...all typed ...fast ...and consistent\n\nFor the small price of 9kb gziped. \u0026nbsp;\u0026nbsp; [🏁Get started now](https://dataclient.io/docs/getting-started/installation)\n\n## Features\n\n- [x] \u003cimg src=\"https://github.com/reactive/data-client/raw/master/packages/react/typescript.svg?sanitize=true\" alt=\"TS\" style=\"max-width: 100%;\"\u003e Strong [Typescript](https://www.typescriptlang.org/) inference\n- [x] 🛌 React [Suspense](https://dataclient.io/docs/getting-started/data-dependency#boundaries) support\n- [x] 🧵 React 18 [Concurrent mode](https://dataclient.io/docs/guides/render-as-you-fetch) compatible\n- [x] 💦 [Partial Hydration Server Side Rendering](https://dataclient.io/docs/guides/ssr)\n- [x] 🎣 [Declarative API](https://dataclient.io/docs/getting-started/data-dependency)\n- [x] 📝 Composition over configuration\n- [x] 💰 [Normalized](https://dataclient.io/docs/concepts/normalization) caching\n- [x] 💥 Tiny bundle footprint\n- [x] 🛑 Automatic overfetching elimination\n- [x] ✨ Fast [optimistic updates](https://dataclient.io/rest/guides/optimistic-updates)\n- [x] 🧘 [Flexible](https://dataclient.io/docs/getting-started/resource) to fit any API design (one size fits all)\n- [x] 🔧 [Debugging and inspection](https://dataclient.io/docs/getting-started/debugging) via browser extension\n- [x] 🌳 Tree-shakable (only use what you need)\n- [x] 🔁 [Subscriptions](https://dataclient.io/docs/api/useSubscription)\n- [x] ♻️ Optional [redux integration](https://dataclient.io/docs/guides/redux)\n- [x] 📙 [Storybook mocking](https://dataclient.io/docs/guides/storybook)\n- [x] 📱 [React Native](https://facebook.github.io/react-native/) support\n- [x] 📱 [Expo](https://dataclient.io/docs/getting-started/installation) support\n- [x] ⚛️ [NextJS](https://dataclient.io/docs/guides/ssr#nextjs) support\n- [x] 🚯 [Declarative cache lifetime policy](https://dataclient.io/docs/concepts/expiry-policy)\n- [x] 🧅 [Composable middlewares](https://dataclient.io/docs/api/Manager)\n- [x] 💽 Global data consistency guarantees\n- [x] 🏇 Automatic race condition elimination\n- [x] 👯 Global referential equality guarantees\n\n## Examples\n\n- Todo: [![GitHub](https://badgen.net/badge/icon/github?icon=github\u0026label)](https://github.com/reactive/data-client/tree/master/examples/todo-app) | [![Sandbox](https://developer.stackblitz.com/img/open_in_stackblitz_small.svg)](https://stackblitz.com/github/reactive/data-client/tree/master/examples/todo-app?file=src%2Fpages%2FHome%2FTodoList.tsx) | [![Edit on CodeSandbox](https://dataclient.io/img/third-party/play-codesandbox-small.svg)](https://codesandbox.io/p/devbox/github/reactive/data-client/tree/master/examples/todo-app)\n- Github: [![GitHub](https://badgen.net/badge/icon/github?icon=github\u0026label)](https://github.com/reactive/data-client/tree/master/examples/github-app) | [![Sandbox](https://developer.stackblitz.com/img/open_in_stackblitz_small.svg)](https://stackblitz.com/github/reactive/data-client/tree/master/examples/github-app?file=src%2Fpages%2FIssueList.tsx)\n- NextJS: [![GitHub](https://badgen.net/badge/icon/github?icon=github\u0026label)](https://github.com/reactive/data-client/tree/master/examples/nextjs) | [![Sandbox](https://developer.stackblitz.com/img/open_in_stackblitz_small.svg)](https://stackblitz.com/github/reactive/data-client/tree/master/examples/nextjs?file=components%2Ftodo%2FTodoList.tsx) | [![Edit on CodeSandbox](https://dataclient.io/img/third-party/play-codesandbox-small.svg)](https://codesandbox.io/p/devbox/github/reactive/data-client/tree/master/examples/nextjs)\n- Websockets: [![GitHub](https://badgen.net/badge/icon/github?icon=github\u0026label)](https://github.com/reactive/coin-app) | [![Sandbox](https://developer.stackblitz.com/img/open_in_stackblitz_small.svg)](https://stackblitz.com/github/reactive/coin-app/tree/master?file=src%2Fresources%2FStreamManager.ts,src%2Fapp%2FCurrencyList.tsx) | [![Website](https://badgen.net/badge/icon/production?icon=vercel\u0026label)](https://coin-app-lake.vercel.app)\n\n## API\n\n### Reactive Applications\n\n- Rendering: [useSuspense()](https://dataclient.io/docs/api/useSuspense), [useLive()](https://dataclient.io/docs/api/useLive), [useCache()](https://dataclient.io/docs/api/useCache), [useDLE()](https://dataclient.io/docs/api/useDLE), [useQuery()](https://dataclient.io/docs/api/useQuery), [useLoading()](https://dataclient.io/docs/api/useLoading), [useDebounce()](https://dataclient.io/docs/api/useDebounce), [useCancelling()](https://dataclient.io/docs/api/useCancelling)\n- Event handling: [useController()](https://dataclient.io/docs/api/useController) returns [Controller](https://dataclient.io/docs/api/Controller)\n  \u003ctable\u003e\n  \u003cthead\u003e\n  \u003ctr\u003e\n  \u003cth\u003eMethod\u003c/th\u003e\n  \u003cth\u003eSubject\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n  \u003ctr\u003e\n  \u003cth colSpan=\"2\" align=\"center\"\u003eFetch\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#fetch\"\u003ectrl.fetch\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eEndpoint + Args\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#fetchIfStale\"\u003ectrl.fetchIfStale\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eEndpoint + Args\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003cth colSpan=\"2\" align=\"center\"\u003eExpiry\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#expireAll\"\u003ectrl.expireAll\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eEndpoint\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#invalidate\"\u003ectrl.invalidate\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eEndpoint + Args\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#invalidateAll\"\u003ectrl.invalidateAll\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eEndpoint\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#resetEntireStore\"\u003ectrl.resetEntireStore\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eEverything\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003cth colSpan=\"2\" align=\"center\"\u003eSet\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#set\"\u003ectrl.set\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eSchema + Args\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#setResponse\"\u003ectrl.setResponse\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eEndpoint + Args\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#setError\"\u003ectrl.setError\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eEndpoint + Args\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#resolve\"\u003ectrl.resolve\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eEndpoint + Args\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003cth colSpan=\"2\" align=\"center\"\u003eSubscription\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#subscribe\"\u003ectrl.subscribe\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eEndpoint + Args\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/api/Controller#unsubscribe\"\u003ectrl.unsubscribe\u003c/a\u003e\u003c/td\u003e\n  \u003ctd\u003eEndpoint + Args\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003c/tbody\u003e\n  \u003c/table\u003e\n\n- Components: [\u0026lt;DataProvider/\u003e](https://dataclient.io/docs/api/DataProvider), [\u0026lt;AsyncBoundary/\u003e](https://dataclient.io/docs/api/AsyncBoundary), [\u0026lt;ErrorBoundary/\u003e](https://dataclient.io/docs/api/ErrorBoundary), [\u0026lt;MockResolver/\u003e](https://dataclient.io/docs/api/MockResolver)\n- Data Mocking: [Fixture](https://dataclient.io/docs/api/Fixtures#successfixture), [Interceptor](https://dataclient.io/docs/api/Fixtures#interceptor), [renderDataHook()](https://dataclient.io/docs/api/renderDataHook)\n- Middleware: [LogoutManager](https://dataclient.io/docs/api/LogoutManager), [NetworkManager](https://dataclient.io/docs/api/NetworkManager), [SubscriptionManager](https://dataclient.io/docs/api/SubscriptionManager), [PollingSubscription](https://dataclient.io/docs/api/PollingSubscription), [DevToolsManager](https://dataclient.io/docs/api/DevToolsManager)\n\n### [Define Data](https://dataclient.io/docs/getting-started/resource)\n\n#### Networking definition\n- [Endpoints](https://dataclient.io/rest/api/Endpoint): [RestEndpoint](https://dataclient.io/rest/api/RestEndpoint), [GQLEndpoint](https://dataclient.io/graphql/api/GQLEndpoint)\n- [Resources](https://dataclient.io/docs/getting-started/resource): [resource()](https://dataclient.io/rest/api/resource), [hookifyResource()](https://dataclient.io/rest/api/hookifyResource)\n\n\u003ctable\u003e\n\u003ccaption\u003e\n\u003ca href=\"https://dataclient.io/docs/concepts/normalization\"\u003eData model\u003c/a\u003e\n\u003c/caption\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eData Type\u003c/th\u003e\n\u003cth\u003eMutable\u003c/th\u003e\n\u003cth\u003eSchema\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003cth\u003e\u003ca href=\"https://dataclient.io/rest/api/schema#queryable\"\u003eQueryable\u003c/a\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd rowSpan=\"4\"\u003e\u003ca href=\"https://en.wikipedia.org/wiki/Object_(computer_science)\"\u003eObject\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/rest/api/Entity\"\u003eEntity\u003c/a\u003e, \u003ca href=\"https://dataclient.io/rest/api/EntityMixin\"\u003eEntityMixin\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003esingle \u003cem\u003eunique\u003c/em\u003e object\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/rest/api/Union\"\u003eUnion(Entity)\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003epolymorphic objects (\u003ccode\u003eA | B\u003c/code\u003e)\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e🛑\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/rest/api/Object\"\u003eObject\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003estatically known keys\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🛑\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/rest/api/Invalidate\"\u003eInvalidate(Entity)\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/docs/concepts/expiry-policy#invalidate-entity\"\u003edelete an entity\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🛑\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd rowSpan=\"3\"\u003e\u003ca href=\"https://en.wikipedia.org/wiki/List_(abstract_data_type)\"\u003eList\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/rest/api/Collection\"\u003eCollection(Array)\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003egrowable lists\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e🛑\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/rest/api/Array\"\u003eArray\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003eimmutable lists\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🛑\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e \u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/rest/api/All\"\u003eAll\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003elist of all entities of a kind\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd rowSpan=\"2\"\u003e\u003ca href=\"https://en.wikipedia.org/wiki/Associative_array\"\u003eMap\u003c/a\u003e\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/rest/api/Collection\"\u003eCollection(Values)\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003egrowable maps\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e🛑\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/rest/api/Values\"\u003eValues\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003eimmutable maps\u003c/td\u003e\n\u003ctd align=\"center\"\u003e🛑\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd rowSpan=\"2\"\u003eany\u003c/td\u003e\n\u003ctd align=\"center\"\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/rest/api/Query\"\u003eQuery(Queryable)\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003ememoized custom transforms\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://dataclient.io/rest/api/Lazy\"\u003eLazy(Schema)\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003edeferred denormalization\u003c/td\u003e\n\u003ctd align=\"center\"\u003e✅\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n","funding_links":["https://github.com/sponsors/ntucker"],"categories":["TypeScript","typescript","HarmonyOS"],"sub_categories":["Windows Manager"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactive%2Fdata-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freactive%2Fdata-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactive%2Fdata-client/lists"}