Initial commit

This commit is contained in:
2026-04-17 23:26:01 +00:00
commit 2ea4ca5d52
409 changed files with 63459 additions and 0 deletions

View File

@@ -0,0 +1,168 @@
---
title: Upload Files Correctly
impact: MEDIUM
impactDescription: Reliable uploads with progress tracking and validation
tags: files, upload, storage, attachments
---
## Upload Files Correctly
File uploads can use plain objects or FormData. Handle large files properly with progress tracking and appropriate error handling.
**Incorrect (naive file upload):**
```javascript
// Missing error handling
async function uploadFile(file) {
await pb.collection('documents').create({
title: file.name,
file: file
});
// No error handling, no progress feedback
}
// Uploading without validation
async function uploadAvatar(file) {
await pb.collection('users').update(userId, {
avatar: file // No size/type check - might fail server-side
});
}
// Base64 upload (inefficient)
async function uploadImage(base64) {
await pb.collection('images').create({
image: base64 // Wrong! PocketBase expects File/Blob
});
}
```
**Correct (proper file uploads):**
```javascript
// Basic upload with object (auto-converts to FormData)
async function uploadDocument(file, metadata) {
try {
const record = await pb.collection('documents').create({
title: metadata.title,
description: metadata.description,
file: file // File object from input
});
return record;
} catch (error) {
if (error.response?.data?.file) {
throw new Error(`File error: ${error.response.data.file.message}`);
}
throw error;
}
}
// Upload multiple files
async function uploadGallery(files, albumId) {
const record = await pb.collection('albums').update(albumId, {
images: files // Array of File objects
});
return record;
}
// FormData for more control
async function uploadWithProgress(file, onProgress) {
const formData = new FormData();
formData.append('title', file.name);
formData.append('file', file);
// Using fetch directly for progress (SDK doesn't expose progress)
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
onProgress(Math.round((e.loaded / e.total) * 100));
}
});
xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText));
} else {
reject(new Error(`Upload failed: ${xhr.status}`));
}
});
xhr.addEventListener('error', () => reject(new Error('Upload failed')));
xhr.open('POST', `${pb.baseURL}/api/collections/documents/records`);
xhr.setRequestHeader('Authorization', pb.authStore.token);
xhr.send(formData);
});
}
// Client-side validation before upload
function validateFile(file, options = {}) {
const {
maxSize = 10 * 1024 * 1024, // 10MB default
allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'],
maxNameLength = 100
} = options;
const errors = [];
if (file.size > maxSize) {
errors.push(`File too large. Max: ${maxSize / 1024 / 1024}MB`);
}
if (!allowedTypes.includes(file.type)) {
errors.push(`Invalid file type: ${file.type}`);
}
if (file.name.length > maxNameLength) {
errors.push(`Filename too long`);
}
return { valid: errors.length === 0, errors };
}
// Complete upload flow
async function handleFileUpload(inputEvent) {
const file = inputEvent.target.files[0];
if (!file) return;
// Validate
const validation = validateFile(file, {
maxSize: 5 * 1024 * 1024,
allowedTypes: ['image/jpeg', 'image/png']
});
if (!validation.valid) {
showError(validation.errors.join(', '));
return;
}
// Upload with progress
try {
setUploading(true);
const record = await uploadWithProgress(file, setProgress);
showSuccess('Upload complete!');
return record;
} catch (error) {
showError(error.message);
} finally {
setUploading(false);
}
}
```
**Deleting files:**
```javascript
// Remove specific file(s) from record
await pb.collection('albums').update(albumId, {
'images-': ['filename1.jpg', 'filename2.jpg'] // Remove these files
});
// Clear all files
await pb.collection('documents').update(docId, {
file: null // Removes the file
});
```
Reference: [PocketBase File Upload](https://pocketbase.io/docs/files-handling/)