POST Method - Global Error Handling
Why Use Global Error Handling?
Configure error handling once globally instead of repeating it in every POST request. Perfect for forms, user creation, and data submission.
Complete Example
import ApiClient, { parseResponseMessage } from "hmm-api";
import { toast } from "sonner";
// Configure once - handles ALL POST requests
const api = new ApiClient({
baseUrl: "https://api.example.com",
returnParsedError: true, // Get clean validation messages
onError: (response) => {
// Handle ALL form errors globally
toast.error(response.error);
// Global validation error handling
if (response.status === 422) {
console.log("Validation failed:", response.error);
}
if (response.status === 401) {
redirectToLogin();
}
},
onSuccess: (response) => {
// Optional: Global success handling
toast.success("Saved successfully!");
},
});
// Usage - No error handling needed!
interface CreateUserRequest {
name: string;
email: string;
}
interface User {
id: number;
name: string;
email: string;
}
const UserForm = () => {
const [loading, setLoading] = useState(false);
const createUser = async (userData: CreateUserRequest) => {
setLoading(true);
// Simple POST - errors handled automatically
const response = await api.post<User>("/users", userData, {
finally: () => setLoading(false),
});
if (response.success) {
// Only handle success case
redirectToUser(response.data.id);
resetForm();
}
};
const uploadFile = async (file: File) => {
const formData = new FormData();
formData.append("file", file);
// File upload - errors handled automatically
const response = await api.post("/upload", formData);
if (response.success) {
console.log("File uploaded:", response.data.url);
}
};
return (
<form
onSubmit={(e) => {
e.preventDefault();
createUser({ name: "John", email: "john@example.com" });
}}
>
<button type="submit" disabled={loading}>
{loading ? "Creating..." : "Create User"}
</button>
</form>
);
};
Key Benefits
- No repetitive error handling - Configure once for all forms
- Consistent validation UX - All form errors shown the same way
- Clean form code - Focus on form logic, not error handling
- Global auth handling - 401 errors handled automatically
Advanced POST Features (v2.0.0)
File Upload with Progress
Track upload progress for better user experience:
const FileUploader = () => {
const [uploadProgress, setUploadProgress] = useState(0);
const [uploading, setUploading] = useState(false);
const handleFileUpload = async (file: File) => {
setUploading(true);
setUploadProgress(0);
const formData = new FormData();
formData.append("file", file);
formData.append("category", "documents");
const response = await api.post("/files/upload", formData, {
onUploadProgress: (progress) => {
setUploadProgress(progress.percentage);
console.log(`Upload: ${progress.percentage}%`);
console.log(`${progress.loaded} / ${progress.total} bytes`);
},
timeout: 60000, // 1 minute timeout for uploads
finally: () => {
setUploading(false);
},
});
if (response.success) {
console.log("File uploaded:", response.data.url);
resetUploadForm();
}
};
return (
<div>
<input
type="file"
onChange={(e) => handleFileUpload(e.target.files[0])}
disabled={uploading}
/>
{uploading && (
<div>
<ProgressBar value={uploadProgress} />
<span>{uploadProgress}% uploaded</span>
</div>
)}
</div>
);
};
POST with Polling
Submit data and poll for processing status:
const processDocument = async (documentData: any) => {
// Step 1: Submit document for processing
const submitResponse = await api.post("/documents/process", documentData);
if (!submitResponse.success) return;
const jobId = submitResponse.data.jobId;
// Step 2: Poll for processing status
const result = await api.get(`/jobs/${jobId}/status`, {
poll: {
interval: 2000, // Check every 2 seconds
maxAttempts: 30,
stopCondition: (response) => {
return response.success && response.data.status === "completed";
},
onPollSuccess: (response, attempt) => {
console.log(`Processing: ${response.data.progress}%`);
updateProcessingProgress(response.data.progress);
},
},
});
if ("finalResponse" in result && result.finalResponse.success) {
console.log("Document processed successfully!");
return result.finalResponse.data;
}
};
Batch Operations with Progress
Handle multiple POST requests with progress tracking:
const batchCreateUsers = async (users: CreateUserRequest[]) => {
const results = [];
let completed = 0;
for (const userData of users) {
const response = await api.post("/users", userData, {
onUploadProgress: (progress) => {
console.log(`User ${completed + 1}: ${progress.percentage}%`);
},
finally: () => {
completed++;
const overallProgress = (completed / users.length) * 100;
updateBatchProgress(overallProgress);
},
});
results.push(response);
if (response.success) {
console.log(`Created user: ${response.data.name}`);
}
}
return results;
};
Form Submission with Cleanup
Proper form handling with automatic cleanup:
const ContactForm = () => {
const [submitting, setSubmitting] = useState(false);
const apiRef = useRef(null);
useEffect(() => {
apiRef.current = new ApiClient({
baseUrl: "/api",
onError: (response) => {
toast.error(response.error);
},
onSuccess: (response) => {
toast.success("Message sent successfully!");
},
});
// Cleanup on unmount
return () => {
if (apiRef.current) {
apiRef.current.destroy();
}
};
}, []);
const handleSubmit = async (formData: ContactFormData) => {
setSubmitting(true);
const response = await apiRef.current.post("/contact", formData, {
timeout: 10000, // 10 second timeout for contact forms
finally: () => {
setSubmitting(false);
},
});
if (response.success) {
resetForm();
redirectToThankYou();
}
};
return (
<form onSubmit={handleSubmit}>
<button type="submit" disabled={submitting}>
{submitting ? "Sending..." : "Send Message"}
</button>
</form>
);
};
When to Override Global Handling
Only override when you need specific behavior:
// Special case: Custom validation error display
const response = await api.post("/users", userData, {
onError: (response) => {
// Custom handling for this specific form
highlightFieldErrors(response.error);
showInlineValidation(response.error);
},
});
// Special case: Silent submission for auto-save
const response = await api.post("/auto-save", draftData, {
showError: false,
showSuccess: false,
timeout: 5000, // Quick timeout for auto-save
});