{"id":13627309,"url":"https://github.com/ngneat/query","last_synced_at":"2025-05-14T19:01:52.853Z","repository":{"id":61405416,"uuid":"545283435","full_name":"ngneat/query","owner":"ngneat","description":"🚀 Powerful asynchronous state management, server-state utilities and data fetching for Angular Applications","archived":false,"fork":false,"pushed_at":"2025-02-13T07:01:26.000Z","size":2151,"stargazers_count":602,"open_issues_count":7,"forks_count":39,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-05-07T18:15:37.458Z","etag":null,"topics":["async","cache","data","fetch","http","pagination","query","stale-while-revalidate","update"],"latest_commit_sha":null,"homepage":"https://ngneat.github.io/query","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ngneat.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.config.js","contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ngneat"}},"created_at":"2022-10-04T05:02:34.000Z","updated_at":"2025-05-03T17:57:10.000Z","dependencies_parsed_at":"2023-02-18T22:00:37.676Z","dependency_job_id":"f3d2734a-2877-4ef2-bfdc-17b9b44c2e30","html_url":"https://github.com/ngneat/query","commit_stats":{"total_commits":268,"total_committers":25,"mean_commits":10.72,"dds":0.4477611940298507,"last_synced_commit":"b0d39bb1788281aac9a5cb98522f21f5efb0cf0f"},"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngneat%2Fquery","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngneat%2Fquery/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngneat%2Fquery/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngneat%2Fquery/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ngneat","download_url":"https://codeload.github.com/ngneat/query/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253534801,"owners_count":21923545,"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":["async","cache","data","fetch","http","pagination","query","stale-while-revalidate","update"],"created_at":"2024-08-01T22:00:32.696Z","updated_at":"2025-05-14T19:01:51.749Z","avatar_url":"https://github.com/ngneat.png","language":"TypeScript","readme":"\u003e The TanStack Query (also known as react-query) adapter for Angular applications\n\nGet rid of granular state management, manual refetching, and async spaghetti code. TanStack Query gives you declarative, always-up-to-date auto-managed queries and mutations that improve your developer experience.\n\n## Features\n\n✅ \u0026nbsp;Observable \u0026 Signal Support  \n✅ \u0026nbsp;Backend agnostic  \n✅ \u0026nbsp;Dedicated Devtools  \n✅ \u0026nbsp;Auto Caching  \n✅ \u0026nbsp;Auto Refetching  \n✅ \u0026nbsp;Window Focus Refetching  \n✅ \u0026nbsp;Polling/Realtime Queries  \n✅ \u0026nbsp;Parallel Queries  \n✅ \u0026nbsp;Dependent Queries  \n✅ \u0026nbsp;Mutations API  \n✅ \u0026nbsp;Automatic Garbage Collection  \n✅ \u0026nbsp;Paginated/Cursor Queries  \n✅ \u0026nbsp;Load-More/Infinite Scroll Queries  \n✅ \u0026nbsp;Request Cancellation  \n✅ \u0026nbsp;Prefetching  \n✅ \u0026nbsp;Offline Support  \n✅ \u0026nbsp;Data Selectors  \n✅ \u0026nbsp;SSR Support\n\n\u003chr /\u003e\n\n[![@ngneat/query](https://github.com/ngneat/query/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/ngneat/query/actions/workflows/ci.yml)\n[![commitizen](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=flat-square)]()\n[![PRs](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)]()\n[![coc-badge](https://img.shields.io/badge/codeof-conduct-ff69b4.svg?style=flat-square)]()\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e5079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release)\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)\n\n## Motivation\n\nDiscover the innovative approach TanStack Query takes to state management, setting it apart from traditional methods. Learn about the motivation behind this design and explore its unique features [here](https://tanstack.com/query/v5/docs/react/overview#motivation).\n\n## Installation\n\n```\nnpm i @ngneat/query\n```\n\n[Stackblitz Example](https://stackblitz.com/edit/stackblitz-starters-bsrgez?file=src%2Fmain.ts)\n\n\u003ePlease be aware that the `@tanstack/query-core` package must also be installed for the functionality to operate correctly.\n\n## Query Client\n\nInject the `QueryClient` [instance](https://tanstack.com/query/v5/docs/reference/QueryClient) through the `injectQueryClient()`\nfunction.\n\n```ts\nimport { injectQueryClient } from '@ngneat/query';\n\n@Injectable({ providedIn: 'root' })\nexport class TodosService {\n  #queryClient = injectQueryClient();\n}\n```\nor provide `QueryClient` [instance](https://tanstack.com/query/v5/docs/reference/QueryClient) manually\n\n```ts\nimport { provideQueryClient } from '@ngneat/query';\nimport { QueryClient } from '@tanstack/query-core';\n\nprovideQueryClient(() =\u003e  new QueryClient())\n```\n\nand then use with\n\n```ts\nimport { injectQueryClient } from '@ngneat/query';\n\n  ...\n  #queryClient = injectQueryClient();\n```\n\n\u003e Functions should run inside an injection context\n\n### Query\n\nUse the `injectQuery` function. Using this function is similar to the [official](https://tanstack.com/query/v5/docs/guides/queries) function.\n\n```ts\nimport { injectQuery } from '@ngneat/query';\n\n@Injectable({ providedIn: 'root' })\nexport class TodosService {\n  #http = inject(HttpClient);\n  #query = injectQuery();\n\n  getTodos() {\n    return this.#query({\n      queryKey: ['todos'] as const,\n      queryFn: () =\u003e {\n        return this.#http.get\u003cTodo[]\u003e(\n          'https://jsonplaceholder.typicode.com/todos',\n        );\n      },\n    });\n  }\n}\n```\n\n\u003e The function should run inside an injection context\n\nFor methods that require a `queryFn` parameter like\n`ensureQueryData`, `fetchQuery`, `prefetchQuery`, `fetchInfiniteQuery` and `prefetchInfiniteQuery` it's possible to use both Promises and Observables. See an example [here](https://github.com/ngneat/query/blob/main/src/app/prefetch-page/resolve.ts#L9).\n\n#### Component Usage - Observable\n\nTo get an observable use the `result$` property:\n\n```ts\n@Component({\n  standalone: true,\n  template: `\n    @if (todos.result$ | async; as result) {\n      @if (result.isLoading) {\n        \u003cp\u003eLoading\u003c/p\u003e\n      }\n      @if (result.isSuccess) {\n        \u003cp\u003e{{ result.data[0].title }}\u003c/p\u003e\n      }\n      @if (result.isError) {\n        \u003cp\u003eError\u003c/p\u003e\n      }\n    }\n  `,\n})\nexport class TodosPageComponent {\n  todos = inject(TodosService).getTodos();\n}\n```\n\n#### Component Usage - Signal\n\nTo get a signal use the `result` property:\n\n```ts\n@Component({\n  standalone: true,\n  template: `\n    @if (todos().isLoading) {\n      Loading\n    }\n    @if (todos().data; as data) {\n      \u003cp\u003e{{ data[0].title }}\u003c/p\u003e\n    }\n    @if (todos().isError) {\n      \u003cp\u003eError\u003c/p\u003e\n    }\n  `,\n})\nexport class TodosPageComponent {\n  todos = inject(TodosService).getTodos().result;\n}\n```\n\n## Typing Query Options\n\nIf you inline query options into `query`, you'll get automatic type inference. However, you might want to extract the query options into a separate function to share them between `query` and e.g. `prefetchQuery`. In that case, you'd lose type inference. To get it back, you can use `queryOptions` helper:\n\n```ts\nimport { queryOptions } from '@ngneat/query';\n\nfunction groupOptions() {\n  return queryOptions({\n    queryKey: ['groups'] as const,\n    queryFn: fetchGroups,\n    staleTime: 5 * 1000,\n  });\n}\n```\n\nFurther, the `queryKey` returned from `queryOptions` knows about the `queryFn` associated with it, and we can leverage that type information to make functions like `queryClient.getQueryData` aware of those types as well:\n\n```ts\n@Injectable({ providedIn: 'root' })\nexport class GroupsService {\n  #client = injectQueryClient();\n  #http = inject(HttpClient);\n\n  groupOptions = queryOptions({\n    queryKey: ['groups'] as const,\n    queryFn: () =\u003e this.#http.get(url),\n    staleTime: 5 * 1000,\n  });\n\n  getCachedGroup() {\n    const data = this.#client.getQueryData(this.groupOptions.queryKey);\n    //     ^? const data: Group[] | undefined\n    return data;\n  }\n}\n```\n\n### Infinite Query\n\nUse the `injectInfiniteQuery` function. Using this function is similar to the [official](https://tanstack.com/query/v5/docs/guides/infinite-queries) function.\n\n```ts\nimport { injectInfiniteQuery } from '@ngneat/query';\n\n@Injectable({ providedIn: 'root' })\nexport class PostsService {\n  #query = injectInfiniteQuery();\n\n  getPosts() {\n    return this.#query({\n      queryKey: ['posts'],\n      queryFn: ({ pageParam }) =\u003e getProjects(pageParam),\n      initialPageParam: 0,\n      getPreviousPageParam: (firstPage) =\u003e firstPage.previousId,\n      getNextPageParam: (lastPage) =\u003e lastPage.nextId,\n    });\n  }\n}\n```\n\n\u003e The function should run inside an injection context\n\n## Mutation\n\nUnlike queries, mutations are typically used to create/update/delete data or perform server side-effects. For this purpose, The library exports the `injectMutation`` function.\n\n```ts\nimport { injectMutation } from '@ngneat/query';\n\n@Injectable({ providedIn: 'root' })\nexport class TodosService {\n  #mutation = injectMutation();\n  #http = inject(HttpClient);\n\n  addTodo() {\n    return this.#mutation({\n      mutationFn: ({ title }) =\u003e\n        this.#http.post\u003cTodo\u003e(`https://jsonplaceholder.typicode.com/todos`, {\n          title,\n        }),\n    });\n  }\n}\n```\n\nThe `variables` in the `mutationFn` callback are the variables that will be passed to the `mutate` function later.\n\nNow create your component in which you want to use your newly created service:\n\n```ts\n@Component({\n  template: `\n    \u003cinput #ref /\u003e\n    \u003cbutton (click)=\"onAddTodo({ title: ref.value })\"\u003eAdd todo\u003c/button\u003e\n\n    @if (addTodo.result$ | async; as result) {\n      @if (result.isLoading) {\n        \u003cp\u003eMutation is loading\u003c/p\u003e\n      }\n      @if (result.isSuccess) {\n        \u003cp\u003eMutation was successful\u003c/p\u003e\n      }\n      @if (result.isError) {\n        \u003cp\u003eMutation encountered an Error\u003c/p\u003e\n      }\n    }\n  `,\n})\nexport class TodosComponent {\n  addTodo = inject(TodosService).addTodo();\n\n  onAddTodo({ title }) {\n    this.addTodo.mutate({ title });\n    // Or\n    this.addTodo.mutateAsync({ title });\n  }\n}\n```\n\nIf you prefer a signal based approach, then you can use the `result` getter function on `addTodo`.\n\n```ts\n@Component({\n  template: `\n    \u003cinput #ref /\u003e\n    \u003cbutton (click)=\"onAddTodo({ title: ref.value })\"\u003eAdd todo\u003c/button\u003e\n\n    @if (addTodo.result(); as result) {\n      @if (result.isLoading) {\n        \u003cp\u003eMutation is loading\u003c/p\u003e\n      }\n      @if (result.isSuccess) {\n        \u003cp\u003eMutation was successful\u003c/p\u003e\n      }\n      @if (result.isError) {\n        \u003cp\u003eMutation encountered an Error\u003c/p\u003e\n      }\n    }\n  `,\n})\nexport class TodosComponent {\n  addTodo = inject(TodosService).addTodo();\n\n  onAddTodo({ title }) {\n    this.addTodo.mutate({ title });\n  }\n}\n```\n\nA more in depth [example](https://github.com/ngneat/query/blob/next/src/app/mutation-page/) can be found on our playground.\n\n## Query Global Options\n\nYou can inject a default config for the underlying `@tanstack/query` instance by using the `provideQueryClientOptions({})` function.\n\n```ts\nimport { provideQueryClientOptions } from '@ngneat/query';\n\nbootstrapApplication(AppComponent, {\n  providers: [\n    provideQueryClientOptions({\n      defaultOptions: {\n        queries: {\n          staleTime: 3000,\n        },\n      },\n    }),\n  ],\n});\n```\n\nIt accept also a function factory if you need an injection context while creating the configuration.\n\n```ts\nimport { provideQueryClientOptions } from '@ngneat/query';\n\nconst withFunctionalFactory: QueryClientConfigFn = () =\u003e {\n  const notificationService = inject(NotificationService);\n\n  return {\n    queryCache: new QueryCache({\n      onError: (error: Error) =\u003e notificationService.notifyError(error),\n    }),\n    defaultOptions: {\n      queries: {\n        staleTime: 3000,\n      },\n    },\n  };\n};\n\nbootstrapApplication(AppComponent, {\n  providers: [provideQueryClientOptions(withFunctionalFactory)],\n});\n```\n\n## Signal Utils\n\n### intersectResults\n\nThe `intersectResults` function is used to merge multiple **_signal_** queries into one.\nIt will return a new base query result that will merge the results of all the queries.\n\n\u003e **Note:** The data will only be mapped if the result is **successful** and otherwise just returned as is on **any other** state.\n\n```ts\nimport { intersectResults } from '@ngneat/query';\n\n@Component({\n  standalone: true,\n  template: `\n    \u003ch1\u003eSignals Intersection\u003c/h1\u003e\n    @if (intersection(); as intersectionResult) {\n      @if (intersectionResult.isLoading) {\n        \u003cp\u003eLoading\u003c/p\u003e\n      }\n      @if (intersectionResult.isSuccess) {\n        \u003cp\u003e{{ intersectionResult.data }}\u003c/p\u003e\n      }\n      @if (intersectionResult.isError) {\n        \u003cp\u003eError\u003c/p\u003e\n      }\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class TodosPageComponent {\n  #todosService = inject(TodosService);\n\n  intersection = intersectResults(\n    [\n      this.#todosService.getTodo('1').result,\n      this.#todosService.getTodo('2').result,\n    ],\n    ([todoOne, todoTwo]) =\u003e todoOne.title + todoTwo.title,\n  );\n\n  intersectionAsObject = intersectResults(\n    {\n      todoOne: this.#todosService.getTodo('1').result,\n      todoTwo: this.#todosService.getTodo('2').result,\n    },\n    ({ todoOne, todoTwo }) =\u003e todoOne.title + todoTwo.title,\n  );\n}\n```\n\n## RxJS Operators\n\n### filterSuccessResult\n\nThe `filterSuccessResult` operator is useful when you want to filter only successful results:\n\n`todosService.getTodos().result$.pipe(filterSuccessResult())`\n\n### filterErrorResult\n\nThe `filterErrorResult` operator is useful when you want to filter only error results:\n\n`todosService.getTodos().result$.pipe(filterErrorResult())`\n\n### tapSuccessResult\n\nThe `tapSuccessResult` operator is useful when you want to run a side effect only when the result is successful:\n\n`todosService.getTodos().result$.pipe(tapSuccessResult(console.log))`\n\n### tapErrorResult\n\nThe `tapErrorResult` operator is useful when you want to run a side effect only when the result is erroring:\n\n`todosService.getTodos().result$.pipe(tapErrorResult(console.log))`\n\n### mapResultData\n\nThe `mapResultData` operator maps the `data` property of the `result` object in case of a successful result.\n\n```ts\nthis.todosService.getTodos().result$.pipe(\n  mapResultData((data) =\u003e {\n    return {\n      todos: data.todos.filter(predicate),\n    };\n  }),\n);\n```\n\n### takeUntilResultFinalize\n\nAn operator that takes values emitted by the source observable until the `isFetching` property on the result is false.  \nIt is intended to be used in scenarios where an observable stream should be listened to until the result has finished fetching (e.g success or error).\n\n`todosService.getTodos().result$.pipe(takeUntilResultFinalize())`\n\n### takeUntilResultSuccess\n\nAn operator that takes values emitted by the source observable until the `isSuccess` property on the result is true.  \nIt is intended to be used in scenarios where an observable stream should be listened to until a successful result is emitted.\n\n`todosService.getTodos().result$.pipe(takeUntilResultSuccess())`\n\n### takeUntilResultError()\n\nAn operator that takes values emitted by the source observable until the `isError` property on the result is true.  \nIt is intended to be used in scenarios where an observable stream should be listened to until an error result is emitted.\n\n`todosService.getTodos().result$.pipe(takeUntilResultError())`\n\n### startWithPendingQueryResult\n\nStarts the observable stream with a pending query result that would also be returned upon creating a normal query:\n\n```ts\nthis.todosService.getTodos().result$.pipe(\n  filterSuccess(),\n  switchMap(() =\u003e someSource),\n  startWithPendingQueryResult(),\n);\n```\n\n### intersectResults$\n\nThe `intersectResults$` operator is used to merge multiple **_observable_** queries into one, this is usually done with a `combineLatest`.\nIt will return a new base query result that will merge the results of all the queries.\n\n\u003e **Note:** The data will only be mapped if the result is **successful** and otherwise just returned as is on **any other** state.\n\n```ts\nconst query = combineLatest({\n  todos: todos.result$,\n  posts: posts.result$,\n}).pipe(\n  intersectResults$(({ todos, posts }) =\u003e { ... })\n)\n\nconst query = combineLatest([todos.result$, posts.result$]).pipe(\n  intersectResults$(([todos, posts]) =\u003e { ... })\n)\n```\n\n## Utils\n\n- `createSuccessObserverResult` - Create success observer result:\n\n```\nimport { createSyncObserverResult } from '@ngneat/query';\n\nresult = of(createSuccessObserverResult(data))\n```\n\n- `createPendingObserverResult` - Create pending observer result\n\n- `updateOptions` - In cases that you want to use the same observer result and update the options you can use the `updateOptions` method:\n\n```ts\n@Component({\n  standalone: true,\n  imports: [RouterModule],\n  template: `\n    \u003ca [queryParams]=\"{ id: 2 }\"\u003eUser 2\u003c/a\u003e\n\n    @if (user().isLoading) {\n      \u003cspan class=\"loader\"\u003e\u003c/span\u003e\n    }\n\n    @if (user().data; as user) {\n      {{ user.email }}\n    }\n  `,\n})\nexport class UsersPageComponent {\n  usersService = inject(UsersService);\n  userResultDef = this.usersService.getUser(\n    +inject(ActivatedRoute).snapshot.queryParams['id'],\n  );\n\n  user = this.userResultDef.result;\n\n  @Input()\n  set id(userId: string) {\n    this.userResultDef.updateOptions(this.usersService.getUserOptions(+userId));\n  }\n}\n```\n\n## Type Utils\n\n- `ObservableQueryResult` - Alias for `Observable\u003cQueryObserverResult\u003cData, Error\u003e\u003e`\n- `SignalQueryResult` - Alias for `Signal\u003cQueryObserverResult\u003cData, Error\u003e\u003e`\n\n## Is Fetching\n\n`injectIsFetching` is a function that returns the number of the queries that your application is loading or fetching in the background (useful for app-wide loading indicators).\n\n### Observable Example\n\n```ts\nimport { injectIsFetching } from '@ngneat/query';\n\nclass TodoComponent {\n  #isFetching = injectIsFetching();\n\n  // How many queries overall are currently fetching data?\n  public isFetching$ = this.#isFetching().result$;\n\n  // How many queries matching the todos prefix are currently fetching?\n  public isFetchingTodos$ = this.#isFetching({ queryKey: ['todos'] }).result$;\n}\n```\n\n### Signal Example\n\n```ts\nimport { injectIsFetching } from '@ngneat/query';\n\nclass TodoComponent {\n  #isFetching = injectIsFetching();\n\n  // How many queries overall are currently fetching data?\n  public isFetching = this.#isFetching().result;\n\n  // How many queries matching the todos prefix are currently fetching?\n  public isFetchingTodos = this.#isFetching({\n    queryKey: ['todos'],\n  }).result;\n}\n```\n\n## Is Mutating\n\n`injectIsMutating` is an optional hook that returns the number of mutations that your application is fetching (useful for app-wide loading indicators).\n\n### Observable Example\n\n```ts\nimport { injectIsMutating } from '@ngneat/query';\n\nclass TodoComponent {\n  #isMutating = injectIsMutating();\n\n  // How many queries overall are currently fetching data?\n  public isFetching$ = this.#isMutating().result$;\n\n  // How many queries matching the todos prefix are currently fetching?\n  public isFetchingTodos$ = this.#isMutating({ queryKey: ['todos'] }).result$;\n}\n```\n\n### Signal Example\n\n```ts\nimport { injectIsMutating } from '@ngneat/query';\n\nclass TodoComponent {\n  #isMutating = injectIsMutating();\n\n  // How many queries overall are currently fetching data?\n  public isFetching = this.#isMutating().result;\n\n  // How many queries matching the todos prefix are currently fetching?\n  public isFetchingTodos = this.#isMutating({\n    queryKey: ['todos'],\n  }).result;\n}\n```\n\n## Devtools\n\nInstall the `@ngneat/query-devtools` package. Lazy load and use it only in `development` environment:\n\n```ts\nimport { provideQueryDevTools } from '@ngneat/query-devtools';\nimport { environment } from 'src/environments/environment';\n\nbootstrapApplication(AppComponent, {\n  providers: [environment.production ? [] : provideQueryDevTools(options)],\n});\n```\n\nSee all the avilable options [here](https://tanstack.com/query/v5/docs/react/devtools#options).\n\n## SSR\n\nOn the Server:\n\n```ts\nimport { provideQueryClient } from '@ngneat/query';\nimport { QueryClient, dehydrate } from '@tanstack/query-core';\nimport { renderApplication } from '@angular/platform-server';\n\nasync function handleRequest(req, res) {\n  const queryClient = new QueryClient();\n  let html = await renderApplication(AppComponent, {\n    providers: [provideQueryClient(queryClient)],\n  });\n\n  const queryState = JSON.stringify(dehydrate(queryClient));\n  html = html.replace(\n    '\u003c/body\u003e',\n    `\u003cscript\u003ewindow.__QUERY_STATE__ = ${queryState}\u003c/script\u003e\u003c/body\u003e`,\n  );\n\n  res.send(html);\n  queryClient.clear();\n}\n```\n\nClient:\n\n```ts\nimport { importProvidersFrom } from '@angular/core';\nimport { bootstrapApplication, BrowserModule } from '@angular/platform-browser';\nimport { provideQueryClient } from '@ngneat/query';\nimport { QueryClient, hydrate } from '@tanstack/query-core';\n\nconst queryClient = new QueryClient();\nconst dehydratedState = JSON.parse(window.__QUERY_STATE__);\nhydrate(queryClient, dehydratedState);\n\nbootstrapApplication(AppComponent, {\n  providers: [\n    importProvidersFrom(\n      BrowserModule.withServerTransition({ appId: 'server-app' }),\n    ),\n    provideQueryClient(queryClient),\n  ],\n});\n```\n\n## Injection Context\n\nThe `queryFn` run inside an injection context so we can do the following if we want:\n\n```ts\nimport { injectQuery } from '@ngneat/query';\n\nexport function getTodos() {\n  const query = injectQuery();\n\n  return query({\n    queryKey: ['todos'] as const,\n    queryFn: () =\u003e {\n      return inject(HttpClient).get\u003cTodo[]\u003e(\n        'https://jsonplaceholder.typicode.com/todos',\n      );\n    },\n  });\n}\n```\n\nWe can also pass a custom injector:\n\n```ts\nexport function getTodos({ injector }: { injector: Injector }) {\n  const query = injectQuery({ injector });\n\n  return query({\n    queryKey: ['todos'] as const,\n    injector,\n    queryFn: ({ signal }) =\u003e {\n      return inject(HttpClient).get\u003cTodo[]\u003e(\n        'https://jsonplaceholder.typicode.com/todos',\n      );\n    },\n  });\n}\n```\n\n## Created By\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://www.netbasal.com\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/6745730?v=4\" width=\"100px;\" alt=\"Netanel Basal\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eNetanel Basal\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\n## Contributors ✨\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/luii\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/8077014?v=4\" width=\"100px;\" alt=\"Netanel Basal\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ePhilipp Czarnetzki\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e\n\nThank goes to all these wonderful [people who contributed](https://github.com/ngneat/query/graphs/contributors) ❤️\n","funding_links":["https://github.com/sponsors/ngneat"],"categories":["Projects by main language","http"],"sub_categories":["angular"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngneat%2Fquery","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fngneat%2Fquery","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngneat%2Fquery/lists"}