Effortlessly bridge Effect HTTP API clients with TanStack Query. Enjoy end-to-end type safety, zero-boilerplate options (queryOptions, mutationOptions, subscriptionOptions), and built-in streaming support out of the box.
- Seamless Integration: Effortlessly map Effect
HttpApiClientendpoints to TanStack Query config objects. - End-to-End Type Safety: Automatically infers inputs (
params,query,payload), response types, and error types directly from your Effect schemas. - Event Streaming Support: Native handling for live streams and Server-Sent Events (SSE) via
subscriptionOptionsanduseSubscription. - Zero Boilerplate: Generates
queryKey, and execution logic under the hood using ES6 Proxies. - Smart Developer Experience: Auto-manages Fiber lifecycles and abort signals, with smart optional parameters when no inputs are required.
Install using your preferred package manager:
# Using npm
npm install @tiesen/effect-tanstack-query @tanstack/react-query effect@beta
# Using yarn
yarn add @tiesen/effect-tanstack-query @tanstack/react-query effect@beta
# Using bun
bun add @tiesen/effect-tanstack-query @tanstack/react-query effect@beta
# Using pnpm
pnpm add @tiesen/effect-tanstack-query @tanstack/react-query effect@betaimport{Schema}from'effect'import{HttpApi,HttpApiEndpoint,HttpApiGroup,HttpApiSchema,}from'effect/unstable/httpapi'classApiGroupextendsHttpApiGroup.make('group').add(HttpApiEndpoint.get('hello','/hello/:name',{success: Schema.String,params: Schema.Struct({name: Schema.String,}),query: Schema.Struct({greeting: Schema.String.pipe(Schema.optionalKey),}),})).add(HttpApiEndpoint.post('goodbye','/goodbye',{success: Schema.String,payload: Schema.Struct({name: Schema.String,}),})).add(HttpApiEndpoint.get('stream','/stream',{success: HttpApiSchema.StreamSse({data: Schema.String,}),})){}exportclassApiextendsHttpApi.make('Api').add(ApiGroup){}import{Context,Layer}from'effect'import{FetchHttpClient}from'effect/unstable/http'import{HttpApiClient}from'effect/unstable/httpapi'classApiClientextendsContext.Service<ApiClient,HttpApiClient.ForApi<typeofApi>>()('ApiClient'){publicstaticlayer=Layer.effect(this,HttpApiClient.make(Api,{baseUrl: 'http://localhost:3000',})).pipe(Layer.provide(FetchHttpClient.layer))}import{ManagedRuntime}from'effect'import{createTanstackQueryOptionsProxy}from'@tiesen/effect-tanstack-query'construntime=ManagedRuntime.make(ApiClient.layer)constapi=createTanstackQueryOptionsProxy(ApiClient,runtime)import{useMutation,useQueryClient,useQuery}from'@tanstack/react-query'import{useSubscription}from'@tiesen/effect-tanstack-query/react'// Query Exampleconstquery=useQuery(api.group.hello.queryOptions({params: {name: 'John'},query: {greeting: 'Hi'},}))// Mutation Exampleconstmutation=useMutation(api.group.goodbye.mutationOptions())mutation.mutate({name: 'John'})// Stream ExampleuseSubscription(api.group.stream.subscriptionOptions(undefined,{onData: (data)=>console.log('Received data:',data),}))// Invalidate Query ExampleconstqueryClient=useQueryClient()voidqueryClient.invalidateQueries({queryKey: api.group.hello.getQueryKey(),})// Call Query / Mutate Directly Exampleconstresult=awaitapi.group.hello.query({params: {name: 'John'},query: {greeting: 'Hi'},})constresult2=awaitapi.group.goodbye.mutate({payload: {name: 'John'}})This project is licensed under the MIT License. See the LICENSE file for details.