API Requests
SmartCommon provides the useApi hook which simplifies API calls with automatic JWT authentication management, token refresh, and error handling.
ky Documentation (HTTP client used)
Configuration
1. Configure the Provider
The ApiProvider must be configured in your LibConfigProvider:
// src/appConfig.js
export const appConfig = {
debug: true,
api: {
prefixUrl: import.meta.env.VITE_API_URL,
timeout: 30000,
debug: true
}
};
// src/App.jsx
import { Provider } from '@cap-rel/smartcommon';
import { appConfig } from './appConfig';
export const App = () => {
return (
<Provider config={appConfig}>
<Router />
</Provider>
);
};
Using useApi
Import the Hook
import { useApi } from '@cap-rel/smartcommon';
Returned Structure
The useApi hook returns an object with the following methods:
| Method | Description |
|---|---|
user |
Connected user object (from gst) |
login(body, options) |
User login, automatically stores tokens |
logout(options) |
Logout, removes tokens |
entities(options) |
Get available entities (before login) |
device(body, options) |
Register/select a device |
public |
ky instance for public requests |
private |
ky instance for authenticated requests |
get(url, options) |
Shortcut for authenticated GET request |
post(url, options) |
Shortcut for authenticated POST request |
put(url, options) |
Shortcut for authenticated PUT request |
patch(url, options) |
Shortcut for authenticated PATCH request |
del(url, options) |
Shortcut for authenticated DELETE request |
Login Request
import { useApi } from '@cap-rel/smartcommon';
import { Input, Button } from '@cap-rel/smartcommon';
export const Login = () => {
const api = useApi();
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const credentials = Object.fromEntries(formData.entries());
try {
const user = await api.login({
...credentials,
rememberMe: true
});
console.log('Logged in:', user);
} catch (error) {
console.error('Login error:', error);
}
};
return (
<form onSubmit={handleSubmit}>
<Input name="login" label="Email" type="email" />
<Input name="password" label="Password" type="password" />
<Button type="submit">Login</Button>
</form>
);
};
Authenticated Requests
For requests requiring authentication, use api.private:
import { useApi } from '@cap-rel/smartcommon';
import { useState, useEffect } from 'react';
import { List, ListItem, Spinner } from '@cap-rel/smartcommon';
export const ItemsList = () => {
const api = useApi();
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchItems = async () => {
try {
const data = await api.private.get('items').json();
setItems(data);
} catch (error) {
console.error('Error:', error);
} finally {
setLoading(false);
}
};
fetchItems();
}, []);
if (loading) return <Spinner />;
return (
<List>
{items.map(item => (
<ListItem key={item.id}>{item.name}</ListItem>
))}
</List>
);
};
POST/PUT/DELETE Requests
const api = useApi();
// POST - Create
const createItem = async (data) => {
return api.private.post('items', { json: data }).json();
};
// PUT - Update
const updateItem = async (id, data) => {
return api.private.put(`items/${id}`, { json: data }).json();
};
// DELETE - Delete
const deleteItem = async (id) => {
return api.del(`items/${id}`);
};
Shortcut Methods
In addition to api.private.get(...).json(), useApi exposes shortcut methods that automatically handle JSON deserialization and errors:
const api = useApi();
// GET
const items = await api.get('items');
// POST with JSON body
const created = await api.post('items', { json: { label: 'New' } });
// PUT
const updated = await api.put(`items/${id}`, { json: data });
// PATCH
const patched = await api.patch(`items/${id}`, { json: { status: 1 } });
// DELETE
await api.del(`items/${id}`);
Raw Option (Binary Data)
To retrieve binary data (images, files), pass raw: true:
// Download a file in binary
const response = await api.get(`file/${hash}/binary`, { raw: true });
const blob = await response.blob();
Silent Option (Suppress Errors)
By default, API errors trigger the onApiError callback (toast display). To suppress them:
// Do not display toast on error
const data = await api.get('optional-endpoint', { silent: true });
Global Error Handling
Configure onApiError in appConfig to centralize API error handling:
// src/appConfig.js
import toast from 'react-hot-toast';
export const appConfig = {
api: {
prefixUrl: import.meta.env.VITE_API_URL,
onApiError: (message) => {
toast.error(message);
},
},
};
When a request fails, useApi:
- Extracts the error message from the JSON response body (
errorormessagefield) - Calls
onApiErrorwith this message (unlesssilent: true) - Also detects application errors (HTTP 200 with
errorfield in body)
Access Connected User
The useApi hook directly exposes the user object:
const api = useApi();
// Direct access to user
const user = api.user;
if (user) {
console.log(user.login, user.accessToken);
}
Public Requests
For requests that do not require authentication:
const api = useApi();
const fetchPublicData = async () => {
return api.public.get('public/info').json();
};
Automatic Features
Token Management
- Access token is automatically added to private request headers
- Token is automatically refreshed before expiration
- On 401 error, a refresh is automatically attempted
Circuit Breaker
- Protection against cascading requests in case of server error
- Temporary blocking of requests after multiple failures
- Automatic detection of internet connection
Automatic Headers
Each request automatically includes:
Authorization: Bearer <token>(private requests)X-DEVICEID: <uuid>(device identification)
Classic Method (Native fetch)
If you prefer to use fetch directly (not recommended):
const API_URL = import.meta.env.VITE_API_URL;
const request = {
method: "POST",
body: JSON.stringify(data),
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `Bearer ${token}`
}
};
fetch(`${API_URL}/items`, request)
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.error(error));
Tip
It is recommended to use useApi rather than native fetch to benefit from automatic token management and circuit breaker.
See Also
- Data Storage - To persist data locally
- Hooks - Full hook documentation
- Back (PHP) - Server-side API route configuration