Published on 2025-03-08
API Client
Published on
API Client
The Igniter API Client provides a seamless way to interact with your backend API from your frontend applications. It offers full type safety, automatic error handling, and integration with popular React hooks for data fetching and mutations.
Setting Up the API Client
The first step is to create your API client by connecting it to your Igniter router:
// src/igniter.client.ts
import { createIgniterClient, useIgniterQueryClient } from '@igniter-js/core/client';
import { AppRouter } from './igniter.router';
/**
* Client for Igniter
*
* This client is used to fetch data on the client-side
* It uses the createIgniterClient function to create a client instance
*/
export const api = createIgniterClient(AppRouter);
/**
* Query client for Igniter
*
* This client provides access to the Igniter query functions
* and handles data fetching with respect to the application router.
* It will enable the necessary hooks for query management.
*/
export const useQueryClient = useIgniterQueryClient<typeof AppRouter>;
Integrating with React
To use the API client in your React application, wrap your app with the Igniter provider:
// app/providers.tsx
import { IgniterProvider } from '@igniter-js/core/client'
export function Providers({ children }: { children: React.ReactNode }) {
return (
<IgniterProvider>
{children}
</IgniterProvider>
)
}
Making API Calls
Using Queries (GET Requests)
The useQuery hook provides a powerful way to fetch data with automatic caching and revalidation:
import { api } from '@/igniter.client'
function UsersList() {
const { data: users, loading, error, refetch } = api.users.list.useQuery({
// Optional configuration
initialData: [], // Initial data while loading
staleTime: 1000 * 60, // Data stays fresh for 1 minute
refetchInterval: 1000 * 30, // Refetch every 30 seconds
refetchOnWindowFocus: true, // Refetch when window regains focus
refetchOnMount: true, // Refetch when component mounts
refetchOnReconnect: true, // Refetch when reconnecting
onLoading: (isLoading) => console.log('Loading:', isLoading),
onRequest: (response) => console.log('Data received:', response)
})
if (loading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return (
<div>
<button onClick={() => refetch()}>Refresh</button>
{users.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
)
}
Using Mutations (POST, PUT, DELETE Requests)
The useMutation hook handles data modifications with loading states and error handling:
function CreateUserForm() {
const { mutate, loading, error } = api.users.create.useMutation({
// Optional configuration
defaultValues: { name: '', email: '' },
onLoading: (isLoading) => console.log('Loading:', isLoading),
onRequest: (response) => console.log('Created user:', response)
})
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
try {
await mutate({
body: {
name: 'John Doe',
email: '[email protected]'
}
})
// Handle success
} catch (error) {
// Handle error
}
}
return (
<form onSubmit={handleSubmit}>
{/* Form fields */}
<button type="submit" disabled={loading}>
{loading ? 'Creating...' : 'Create User'}
</button>
{error && <div>Error: {error.message}</div>}
</form>
)
}
Managing Cache
You can invalidate queries manually or automatically after mutations:
function AdminPanel() {
const queryClient = useQueryClient()
// Invalidate specific queries
const invalidateUsers = () => {
queryClient.invalidate('users.list')
}
// Invalidate multiple queries
const invalidateAll = () => {
queryClient.invalidate([
'users.list',
'users.get'
])
}
return (
<button onClick={invalidateUsers}>
Refresh Users
</button>
)
}
Type Safety
The Igniter API Client provides full type inference for your API:
// All these types are automatically inferred
import { InferOutput, InferInput } from '@igniter-js/core/client'
type User = InferOutput<typeof api.users.get>
type CreateUserInput = InferInput<typeof api.users.create>
// TypeScript will show errors for invalid inputs
api.users.create.useMutation({
onRequest: (data) => {
data.id // ✅ Typed as string
data.invalid // ❌ TypeScript error
}
})
Server-Side Usage
Next.js App Router Integration
You can use direct server calls with React Server Components:
// app/users/page.tsx
import { api } from '@/igniter.client'
export default async function UsersPage() {
const users = await api.users.list.call()
return (
<div>
{users.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
)
}
Server Actions
// app/users/actions.ts
'use server'
import { api } from '@/igniter.client'
export async function createUser(formData: FormData) {
const name = formData.get('name') as string
const email = formData.get('email') as string
return api.users.create.call({
body: { name, email }
})
}
// app/users/create-form.tsx
export function CreateUserForm() {
return (
<form action={createUser}>
<input name="name" />
<input name="email" type="email" />
<button type="submit">Create User</button>
</form>
)
}
Error Handling
The API client provides robust error handling capabilities:
function UserProfile() {
const { data, error, retry } = api.users.get.useQuery({
onError: (error) => {
console.error('Failed to fetch user:', error)
},
retry: 3, // Retry failed requests
retryDelay: 1000, // Wait 1 second between retries
})
if (error) {
return (
<div>
Error loading profile
<button onClick={retry}>Try Again</button>
</div>
)
}
return <div>{/* User profile content */}</div>
}
Testing
The API client can be used in tests to verify your API functionality:
import { api } from '@/igniter.client'
describe('User API', () => {
it('should create a user', async () => {
const result = await api.users.create.call({
body: {
name: 'Test User',
email: '[email protected]'
}
})
expect(result.status).toBe(201)
expect(result.data).toHaveProperty('id')
})
})
By using the Igniter API Client, you get a fully type-safe way to interact with your backend API, with built-in support for caching, error handling, and React integration.
Quick Tip
Always implement proper error handling and reconnection logic in your SSE clients to ensure a robust user experience.