Core Concepts
Understanding how Builder works will help you use it effectively. Don't worry, it's simpler than it looks!
The Three Key Pieces
Builder revolves around three main concepts:
1. Register - Your Data Structure
A plain JavaScript object containing your keys, values, and functions:
const register = {
users: {
list: () => fetch('/api/users'),
detail: (id: number) => fetch(`/api/users/${id}`)
}
};Think of it as: Your table of contents or API map.
2. createBuilder - The Transformer
The function that transforms your register into a builder:
import { createBuilder } from '@ibnlanre/builder';
const api = createBuilder(register);Think of it as: The magic spell that adds superpowers to your object.
3. Builder - The Enhanced Object
The result: your register with special $use and $get methods added:
// Access values (same as before)
api.$use.users.detail(5);
// Generate keys (the superpower!)
api.users.detail.$use(5); // ['users', 'detail', 5]Think of it as: Your register, but with automatic key generation.
How They Work Together
// 1. Define your structure (Register)
const register = {
products: {
list: () => fetch('/api/products')
}
};
// 2. Transform it (createBuilder)
const store = createBuilder(register);
// 3. Use it (Builder)
store.products.list.$use(); // ['products', 'list'] - The key
await store.$use.products.list(); // Calls the API - The valueFramework Agnostic
Builder works with any JavaScript framework or library:
// React + TanStack Query
import { useQuery } from '@tanstack/react-query';
const { data } = useQuery({
queryKey: api.posts.list.$use(),
queryFn: api.$use.posts.list
});
// Vue + VueQuery
import { useQuery } from '@tanstack/vue-query';
const { data } = useQuery({
queryKey: api.posts.list.$use(),
queryFn: api.$use.posts.list
});
// Svelte + SWR
import useSWR from 'swr';
const { data } = useSWR(api.$get('posts.list'), api.$use.posts.list);
// Vanilla JavaScript
const cacheKey = api.products.detail.$use(123).join('.');
localStorage.setItem(cacheKey, JSON.stringify(data));Builder doesn't care what framework you use. It's just JavaScript objects and arrays.
TypeScript: Optional but Recommended
Builder is written in TypeScript, but you don't have to use it:
Without TypeScript (JavaScript)
const api = createBuilder({
users: {
list: () => fetch('/api/users').then(r => r.json())
}
});
// Works fine, but no autocomplete
api.users.list.$use();With TypeScript
const api = createBuilder({
users: {
list: async (): Promise<User[]> => {
return fetch('/api/users').then(r => r.json());
},
detail: async (id: number): Promise<User> => {
return fetch(`/api/users/${id}`).then(r => r.json());
}
}
});
// ✅ Autocomplete suggests: users, $use, $get
api.users.
// ✅ TypeScript enforces correct parameters
api.users.detail.$use(123); // Works
api.users.detail.$use('abc'); // Error!
// ✅ Return types are inferred
const user: User = await api.$use.users.detail(1);Benefits of TypeScript:
- Autocomplete for all keys
- Compile-time error checking
- Better IntelliSense documentation
- Safer refactoring
Quick Reference
| Concept | What It Is | Example |
|---|---|---|
| Register | Your plain object | { users: { list: () => {...} } } |
| createBuilder | Transformer function | createBuilder(register) |
| Builder | Enhanced object | api.users.list.$use() |
| $use | Access values (root) Generate keys (nodes) | api.$use.users.list()api.users.list.$use() |
| $get | Flexible key generation | api.users.list.$get('extra', 'params') |
| Prefix | Namespace for all keys | createBuilder(register, { prefix: ['v2'] }) |
Practical Workflow
Here's how you'd typically use Builder in a project:
- Define your register (one time, in one file)
// api/index.ts
const register = {
users: { /* ... */ },
posts: { /* ... */ },
comments: { /* ... */ }
};
export const api = createBuilder(register);- Import where needed
// components/UserList.tsx
import { api } from '../api';- Use for keys and values
const { data } = useQuery({
queryKey: api.users.list.$use(),
queryFn: api.$use.users.list
});- Refactor easily
const register = {
accounts: { /* ... */ }, // Changed 'users' to 'accounts'?
};
// Update once in register, everywhere updates automatically
Next Steps
Ready to dive deeper? Learn about each piece:
- Registers - How to structure your data
- createBuilder - Using prefixes and options
- Builder Object - Understanding get
Or jump straight to practical examples:
- Managing State - Real-world TanStack Query examples
- Constructing Keys - Advanced key patterns