Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tim-smart/effect-atom/llms.txt

Use this file to discover all available pages before exploring further.

Overview

AtomHttpApi provides a reactive HTTP API client integration for Effect Atom, built on top of @effect/platform’s HttpApi. It enables you to create type-safe HTTP clients with automatic reactivity, caching, and state management.

Tag

Creates an AtomHttpApi client tag with reactive query and mutation methods.
id
string
required
Unique identifier for the HTTP API client service.
options
object
required
Configuration options for the HTTP API client.

Returns

AtomHttpApiClient
object
A tagged HTTP API client with reactive methods.

Example

import * as HttpApi from "@effect/platform/HttpApi"
import * as HttpApiClient from "@effect/platform/HttpApiClient"
import * as AtomHttpApi from "@effect-atom/atom/AtomHttpApi"
import * as Layer from "effect/Layer"

// Define your HTTP API
const MyApi = HttpApi.make("MyApi").pipe(
  HttpApi.addGroup(
    HttpApiGroup.make("Users").pipe(
      HttpApiGroup.addEndpoint(
        HttpApiEndpoint.get("getUser", "/users/:id").pipe(
          HttpApiEndpoint.setPath(Schema.Struct({ id: Schema.String })),
          HttpApiEndpoint.setSuccess(Schema.Struct({ 
            id: Schema.String, 
            name: Schema.String 
          }))
        )
      )
    )
  )
)

// Create the HTTP API client
const MyApiClient = AtomHttpApi.Tag<MyApiClient>()("MyApiClient", {
  api: MyApi,
  httpClient: HttpClient.layer,
  baseUrl: "https://api.example.com"
})

query

Creates a reactive atom that executes an HTTP query. The atom automatically caches results and supports reactivity keys for cache invalidation.
group
GroupName
required
The API group name containing the endpoint.
endpoint
Name
required
The endpoint name to query.
request
object
required
Request parameters for the endpoint.

Returns

atom
Atom<Result<Success, Error>>
A reactive atom containing the query result.

Example

import * as Duration from "effect/Duration"

// Create a query atom for fetching user data
const userAtom = MyApiClient.query("Users", "getUser", {
  path: { id: "user-123" },
  timeToLive: Duration.minutes(5),
  reactivityKeys: ["users", "user-123"]
})

// Use in a React component
function UserProfile({ userId }: { userId: string }) {
  const userAtom = MyApiClient.query("Users", "getUser", {
    path: { id: userId }
  })
  
  const user = useAtomValue(userAtom)
  
  return Result.match(user, {
    Initial: () => <div>Loading...</div>,
    Pending: () => <div>Loading...</div>,
    Success: (data) => <div>Hello {data.name}!</div>,
    Failure: (error) => <div>Error: {error.message}</div>
  })
}
Query atoms use structural equality for request parameters. Two queries with the same parameters will share the same atom instance and cached data.

mutation

Creates a mutation function for executing HTTP requests that modify data. Mutations integrate with the reactivity system to automatically invalidate related query caches.
group
GroupName
required
The API group name containing the endpoint.
endpoint
Name
required
The endpoint name for the mutation.
options
object
Configuration options for the mutation.

Returns

mutationFn
AtomResultFn
A function that accepts request parameters and returns a Result.The request parameter includes:
  • path - Path parameters
  • urlParams - Query parameters
  • payload - Request body
  • headers - HTTP headers
  • reactivityKeys - Keys to invalidate after successful mutation

Example

// Create a mutation for updating user data
const updateUser = MyApiClient.mutation("Users", "updateUser")

// Use in a React component
function UpdateUserForm({ userId }: { userId: string }) {
  const updateUserMutation = MyApiClient.mutation("Users", "updateUser")
  const result = useAtomValue(updateUserMutation)
  
  const handleSubmit = async (name: string) => {
    await updateUserMutation({
      path: { id: userId },
      payload: { name },
      // Invalidate user queries after successful update
      reactivityKeys: ["users", userId]
    })
  }
  
  return (
    <form onSubmit={(e) => {
      e.preventDefault()
      handleSubmit(e.currentTarget.name.value)
    }}>
      <input name="name" placeholder="User name" />
      <button type="submit">
        {Result.isPending(result) ? "Updating..." : "Update"}
      </button>
      {Result.isFailure(result) && (
        <div>Error: {result.error.message}</div>
      )}
    </form>
  )
}
Mutations automatically invalidate queries with matching reactivity keys. Make sure to use consistent keys across your queries and mutations for proper cache invalidation.

Complete integration example

Here’s a complete example showing how to set up and use AtomHttpApi in an application:
import * as HttpApi from "@effect/platform/HttpApi"
import * as HttpApiClient from "@effect/platform/HttpApiClient"
import * as HttpApiEndpoint from "@effect/platform/HttpApiEndpoint"
import * as HttpApiGroup from "@effect/platform/HttpApiGroup"
import * as HttpClient from "@effect/platform/HttpClient"
import * as AtomHttpApi from "@effect-atom/atom/AtomHttpApi"
import * as Schema from "effect/Schema"
import * as Layer from "effect/Layer"
import * as Duration from "effect/Duration"

// 1. Define your data schemas
const User = Schema.Struct({
  id: Schema.String,
  name: Schema.String,
  email: Schema.String
})

const CreateUserPayload = Schema.Struct({
  name: Schema.String,
  email: Schema.String
})

// 2. Define your HTTP API
const UsersApi = HttpApi.make("UsersApi").pipe(
  HttpApi.addGroup(
    HttpApiGroup.make("Users").pipe(
      HttpApiGroup.addEndpoint(
        HttpApiEndpoint.get("getUser", "/users/:id").pipe(
          HttpApiEndpoint.setPath(Schema.Struct({ id: Schema.String })),
          HttpApiEndpoint.setSuccess(User)
        )
      ),
      HttpApiGroup.addEndpoint(
        HttpApiEndpoint.get("listUsers", "/users").pipe(
          HttpApiEndpoint.setSuccess(Schema.Array(User))
        )
      ),
      HttpApiGroup.addEndpoint(
        HttpApiEndpoint.post("createUser", "/users").pipe(
          HttpApiEndpoint.setPayload(CreateUserPayload),
          HttpApiEndpoint.setSuccess(User)
        )
      )
    )
  )
)

// 3. Create the AtomHttpApi client
interface UsersApiClient {}
const UsersApiClient = AtomHttpApi.Tag<UsersApiClient>()("UsersApiClient", {
  api: UsersApi,
  httpClient: HttpClient.layer,
  baseUrl: "https://api.example.com"
})

// 4. Use in your application
function UsersList() {
  const usersAtom = UsersApiClient.query("Users", "listUsers", {
    timeToLive: Duration.minutes(5),
    reactivityKeys: ["users"]
  })
  
  const users = useAtomValue(usersAtom)
  const createUser = UsersApiClient.mutation("Users", "createUser")
  
  return Result.match(users, {
    Initial: () => <div>Loading...</div>,
    Pending: () => <div>Loading...</div>,
    Success: (data) => (
      <div>
        <h1>Users</h1>
        <ul>
          {data.map(user => (
            <li key={user.id}>{user.name} ({user.email})</li>
          ))}
        </ul>
        <button onClick={async () => {
          await createUser({
            payload: { name: "New User", email: "new@example.com" },
            reactivityKeys: ["users"] // Invalidates the users list
          })
        }}>
          Add User
        </button>
      </div>
    ),
    Failure: (error) => <div>Error loading users</div>
  })
}

Type safety

AtomHttpApi maintains full type safety from your HTTP API definition:
  • Request parameters are typed based on endpoint path, query, payload, and header schemas
  • Success responses are typed according to the endpoint’s success schema
  • Errors include the endpoint error type, group errors, HTTP client errors, and parse errors
  • Auto-completion works for group names, endpoint names, and all request parameters
The client uses structural equality for caching, so atoms with identical request parameters will share the same cached instance.

Build docs developers (and LLMs) love