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'
class ApiGroup extends HttpApiGroup.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,
}),
})
) {}
export class Api extends HttpApi.make('Api').add(ApiGroup) {}import { Context, Layer } from 'effect'
import { FetchHttpClient } from 'effect/unstable/http'
import { HttpApiClient } from 'effect/unstable/httpapi'
class ApiClient extends Context.Service<
ApiClient,
HttpApiClient.ForApi<typeof Api>
>()('ApiClient') {
public static layer = 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'
const runtime = ManagedRuntime.make(ApiClient.layer)
const api = createTanstackQueryOptionsProxy(ApiClient, runtime)import { useMutation, useQueryClient, useQuery } from '@tanstack/react-query'
import { useSubscription } from '@tiesen/effect-tanstack-query/react'
// Query Example
const query = useQuery(
api.group.hello.queryOptions({
params: { name: 'John' },
query: { greeting: 'Hi' },
})
)
// Mutation Example
const mutation = useMutation(api.group.goodbye.mutationOptions())
mutation.mutate({ name: 'John' })
// Stream Example
useSubscription(
api.group.stream.subscriptionOptions(undefined, {
onData: (data) => console.log('Received data:', data),
})
)
// Invalidate Query Example
const queryClient = useQueryClient()
void queryClient.invalidateQueries({
queryKey: api.group.hello.getQueryKey(),
})This project is licensed under the MIT License. See the LICENSE file for details.