How to Use It ​
This guide covers the essential patterns and common scenarios for using @pubflow/flowfull-client in your applications.
Installation ​
First, install the package:
npm install @pubflow/flowfull-clientyarn add @pubflow/flowfull-clientpnpm add @pubflow/flowfull-clientbun add @pubflow/flowfull-clientBasic Setup ​
Creating a Client ​
The simplest way to create a client is using the createFlowfull factory function:
import { createFlowfull } from '@pubflow/flowfull-client';
// Basic setup
const api = createFlowfull('https://api.myapp.com');With Configuration ​
You can customize the client with various options:
const api = createFlowfull('https://api.myapp.com', {
// Session management
sessionId: 'your-session-id', // Manual session
includeSession: true, // Include session in requests (default: true)
sessionHeader: 'X-Session-Id', // Custom session header (default: 'X-Session-Id')
// Custom headers
headers: {
'X-API-Version': 'v2',
'X-Client-ID': 'web-app'
},
// Retry configuration
retryAttempts: 3, // Number of retry attempts (default: 3)
// Timeout
timeout: 30000, // Request timeout in ms (default: 30000)
// Callbacks
onRequest: async (config) => {
console.log('Request:', config);
},
onResponse: async (response) => {
console.log('Response:', response);
},
onError: (error) => {
console.error('Error:', error);
}
});Making Requests ​
Simple HTTP Methods ​
GET Request ​
// Simple GET
const response = await api.get('/users');
// GET with query parameters
const response = await api.get('/users', {
params: {
page: 1,
limit: 20
}
});
// GET with custom headers
const response = await api.get('/users', {
headers: {
'X-Custom-Header': 'value'
}
});POST Request ​
// Create a new user
const newUser = {
name: 'John Doe',
email: 'john@example.com',
age: 30
};
const response = await api.post('/users', newUser);
if (response.success) {
console.log('Created user:', response.data);
} else {
console.error('Error:', response.error);
}PUT Request ​
// Update entire resource
const updates = {
name: 'John Updated',
email: 'john.updated@example.com',
age: 31
};
const response = await api.put('/users/123', updates);PATCH Request ​
// Partial update
const response = await api.patch('/users/123', {
status: 'active'
});DELETE Request ​
// Delete a resource
const response = await api.delete('/users/123');
if (response.success) {
console.log('User deleted successfully');
}Using the Query Builder ​
The query builder provides a powerful, chainable API for building complex queries.
Basic Filtering ​
// Simple equality filter
const response = await api
.query('/users')
.where('status', 'active')
.get();
// Multiple filters
const response = await api
.query('/products')
.where('status', 'active')
.where('price', 'gte', 50)
.where('price', 'lte', 200)
.get();Using Filter Operators ​
Import and use the 14 filter operators:
import {
eq, ne, gt, gte, lt, lte, // Comparison
like, ilike, startsWith, endsWith, // String
inOp, notIn, // Array
isNull, isNotNull, // Null
between, notBetween // Range
} from '@pubflow/flowfull-client';
// Comparison operators
const adults = await api
.query('/users')
.where('age', gte(18))
.get();
// String operators
const gmailUsers = await api
.query('/users')
.where('email', endsWith('@gmail.com'))
.get();
// Array operators
const activeUsers = await api
.query('/users')
.where('status', inOp(['active', 'verified', 'premium']))
.get();
// Null operators
const verifiedUsers = await api
.query('/users')
.where('verified_at', isNotNull())
.get();
// Range operators
const midRangeProducts = await api
.query('/products')
.where('price', between(50, 200))
.get();Search ​
Add full-text search to your queries:
// Simple search
const results = await api
.query('/products')
.search('laptop')
.get();
// Search with filters
const results = await api
.query('/products')
.search('laptop')
.where('category', 'electronics')
.where('price', lte(1000))
.get();
// Using shorthand 'q()'
const results = await api
.query('/products')
.q('laptop')
.get();Pagination ​
// Page-based pagination
const response = await api
.query('/users')
.page(2)
.limit(25)
.get();
// Access pagination metadata
if (response.success && response.meta) {
console.log(`Page ${response.meta.page} of ${response.meta.totalPages}`);
console.log(`Total items: ${response.meta.total}`);
}
// Offset-based pagination
const response = await api
.query('/users')
.offset(50)
.limit(25)
.get();Sorting ​
// Single sort
const response = await api
.query('/users')
.sort('name', 'asc')
.get();
// Multiple sorts
const response = await api
.query('/users')
.sort('status', 'asc')
.sort('name', 'asc')
.get();
// Using orderBy alias
const response = await api
.query('/users')
.orderBy('created_at', 'desc')
.get();Custom Parameters ​
Add custom query parameters:
// Single parameter
const response = await api
.query('/users')
.param('include', 'profile')
.get();
// Multiple parameters
const response = await api
.query('/users')
.params({
include: 'profile,settings',
fields: 'id,name,email',
expand: 'organization'
})
.get();Custom Headers ​
Add custom headers to specific requests:
// Single header
const response = await api
.query('/users')
.header('X-API-Version', 'v2')
.get();
// Multiple headers
const response = await api
.query('/users')
.headers({
'X-API-Version': 'v2',
'X-Client-ID': 'web-app'
})
.get();Complex Queries ​
Combine everything for powerful queries:
const response = await api
.query('/products')
.search('laptop') // Full-text search
.where('category', 'electronics') // Category filter
.where('price', between(500, 2000)) // Price range
.where('rating', gte(4)) // Minimum rating
.where('stock', gt(0)) // In stock
.where('status', inOp(['active', 'new'])) // Status filter
.sort('price', 'asc') // Sort by price
.page(1) // First page
.limit(20) // 20 items
.param('include', 'images,reviews') // Include relations
.get();Session Management ​
Auto-Detection (Recommended) ​
The client automatically detects sessions from storage:
// Browser: Searches localStorage for common session keys
// React Native: Searches AsyncStorage for common session keys
const api = createFlowfull('https://api.myapp.com');
// Common session keys searched:
// - pubflow_session_id
// - session_id
// - sessionId
// - X-Session-ID
// - x-session-idManual Session ​
Provide a session ID directly:
const api = createFlowfull('https://api.myapp.com', {
sessionId: 'your-session-id-here'
});Dynamic Session ​
Use a function to retrieve the session dynamically:
const api = createFlowfull('https://api.myapp.com', {
getSessionId: async () => {
// Get from secure storage
return await SecureStore.getItemAsync('session_id');
}
});Custom Storage ​
Provide a custom storage adapter:
const api = createFlowfull('https://api.myapp.com', {
storage: {
getItem: async (key) => {
return await myCustomStorage.get(key);
},
setItem: async (key, value) => {
await myCustomStorage.set(key, value);
},
removeItem: async (key) => {
await myCustomStorage.delete(key);
}
}
});Sessionless Requests ​
For public APIs or login endpoints:
// Disable sessions globally
const api = createFlowfull('https://api.myapp.com', {
includeSession: false
});
// Or per-request
const response = await api.get('/public/data', {
includeSession: false
});Session Methods ​
Manage sessions programmatically:
// Get current session
const sessionId = await api.getSessionId();
// Set session
api.setSessionId('new-session-id');
// Clear session
api.clearSession();
// Check if session exists
const hasSession = await api.hasSession();Response Handling ​
Standard Response Format ​
All responses follow a consistent format:
interface ApiResponse<T> {
success: boolean; // true if HTTP 2xx
data?: T; // Response data
error?: string; // Error message (if failed)
message?: string; // Additional message
status: number; // HTTP status code
meta?: { // Pagination metadata
page?: number;
limit?: number;
total?: number;
totalPages?: number;
};
}Handling Success ​
const response = await api.get('/users');
if (response.success) {
console.log('Data:', response.data);
// Check for pagination
if (response.meta) {
console.log(`Page ${response.meta.page} of ${response.meta.totalPages}`);
console.log(`Total items: ${response.meta.total}`);
}
}Handling Errors ​
const response = await api.post('/users', userData);
if (!response.success) {
console.error(`Error ${response.status}: ${response.error}`);
// Handle specific error codes
switch (response.status) {
case 400:
console.error('Bad request:', response.error);
break;
case 401:
console.error('Unauthorized - please login');
break;
case 403:
console.error('Forbidden - insufficient permissions');
break;
case 404:
console.error('Not found');
break;
case 500:
console.error('Server error');
break;
}
}TypeScript Type Safety ​
interface User {
id: string;
name: string;
email: string;
}
// Type the response
const response = await api.get<User[]>('/users');
if (response.success) {
// TypeScript knows response.data is User[]
response.data.forEach(user => {
console.log(user.name); // ✅ Autocomplete works
});
}Advanced Features ​
Interceptors ​
Modify requests and responses globally:
// Request interceptor
api.addRequestInterceptor(async (config) => {
// Add timestamp to all requests
config.headers['X-Request-Time'] = new Date().toISOString();
// Add device info
config.headers['X-Device-ID'] = await getDeviceId();
// Log request
console.log(`[${config.method}] ${config.url}`);
return config;
});
// Response interceptor
api.addResponseInterceptor(async (response) => {
// Log all errors
if (!response.success) {
console.error('API Error:', response.error);
}
// Transform data
if (response.success && response.data) {
// Convert dates
if (Array.isArray(response.data)) {
response.data = response.data.map(item => ({
...item,
created_at: new Date(item.created_at)
}));
}
}
return response;
});Custom Headers ​
Set default headers for all requests:
// Set header
api.setHeader('X-API-Key', 'your-api-key');
api.setHeader('X-Client-Version', '1.0.0');
// Remove header
api.removeHeader('X-API-Key');Timeout Configuration ​
// Global timeout
const api = createFlowfull('https://api.myapp.com', {
timeout: 30000 // 30 seconds
});
// Per-request timeout
const response = await api.get('/users', {
timeout: 5000 // 5 seconds
});Abort Requests ​
// Create abort controller
const controller = new AbortController();
// Make request with signal
const promise = api.get('/users', {
signal: controller.signal
});
// Abort after 5 seconds
setTimeout(() => {
controller.abort();
}, 5000);
try {
const response = await promise;
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request aborted');
}
}Platform-Specific Usage ​
Browser / React ​
import { createFlowfull } from '@pubflow/flowfull-client';
// Auto-detects localStorage
const api = createFlowfull('https://api.myapp.com');
// Use in React component
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
const fetchUsers = async () => {
const response = await api.get('/users');
if (response.success) {
setUsers(response.data);
}
};
fetchUsers();
}, []);
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}React Native / Expo ​
import { createFlowfull } from '@pubflow/flowfull-client';
import AsyncStorage from '@react-native-async-storage/async-storage';
// Auto-detects AsyncStorage
const api = createFlowfull('https://api.myapp.com');
// Use in React Native component
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
const fetchUsers = async () => {
const response = await api.get('/users');
if (response.success) {
setUsers(response.data);
}
};
fetchUsers();
}, []);
return (
<FlatList
data={users}
renderItem={({ item }) => <Text>{item.name}</Text>}
keyExtractor={item => item.id}
/>
);
}Node.js / Bun ​
import { createFlowfull } from '@pubflow/flowfull-client';
// Manual session management
const api = createFlowfull('https://api.myapp.com', {
sessionId: process.env.SESSION_ID
});
// Use in server
async function getUsers() {
const response = await api.get('/users');
return response.data;
}Common Patterns ​
Login Flow ​
// Create client without session
const api = createFlowfull('https://api.myapp.com', {
includeSession: false
});
// Login
const loginResponse = await api.post('/auth/login', {
email: 'user@example.com',
password: 'password123'
}, {
includeSession: false // Don't include session for login
});
if (loginResponse.success) {
// Set session after successful login
api.setSessionId(loginResponse.data.session_id);
// Now all requests include session
const profile = await api.get('/profile');
}Logout Flow ​
// Logout
await api.post('/auth/logout');
// Clear session
api.clearSession();Pagination Loop ​
async function getAllUsers() {
const allUsers = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await api
.query('/users')
.page(page)
.limit(100)
.get();
if (response.success) {
allUsers.push(...response.data);
hasMore = response.meta && response.meta.page < response.meta.totalPages;
page++;
} else {
hasMore = false;
}
}
return allUsers;
}Error Retry ​
async function fetchWithRetry(endpoint, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await api.get(endpoint);
if (response.success) {
return response;
}
// Wait before retry (exponential backoff)
if (i < maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
}
}
throw new Error('Max retries exceeded');
}Next Steps ​
- Tutorial - Step-by-step tutorial with complete examples
- API Reference - Complete API documentation
- Examples - Real-world examples