Your CarbonIQ API now supports multiple ways to link images to waste reports:
- Two-step process: Upload image first, then create report with image URL
- Single-step process: Create report with image in one request
- Add image later: Upload image to existing report
POST /reports/upload
Authorization: Bearer <token>
Content-Type: multipart/form-data
Form Data:
- file: [image file]Response:
{
"filename": "1723567623_user_photo.jpg",
"url": "/static/images/1723567623_user_photo.jpg",
"size": 1024000,
"uploaded_by": "user@example.com",
"uploaded_at": "2025-08-13T17:00:00.000000"
}POST /reports/
Authorization: Bearer <token>
Content-Type: application/json
{
"student_id": "student123",
"waste_type": "recyclable_plastic",
"location": {
"type": "Point",
"coordinates": [-74.006, 40.7128]
},
"image_url": "/static/images/1723567623_user_photo.jpg",
"safe": true,
"urban_area": true
}POST /reports/with-image
Authorization: Bearer <token>
Content-Type: multipart/form-data
Form Data:
- student_id: "student123"
- waste_type: "recyclable_plastic"
- longitude: -74.006
- latitude: 40.7128
- safe: true
- urban_area: true
- file: [image file]Response:
{
"id": "report_id_here",
"student_id": "student123",
"waste_type": "recyclable_plastic",
"image_url": "/static/images/1723567623_user_photo.jpg",
"location": {
"type": "Point",
"coordinates": [-74.006, 40.7128]
},
"status": "new",
"priority": 0,
"created_by": "user@example.com"
}PATCH /reports/{report_id}/image
Authorization: Bearer <token>
Content-Type: multipart/form-data
Form Data:
- file: [image file]Response:
{
"message": "Image added to report successfully",
"report_id": "report_id_here",
"image_url": "/static/images/1723567623_user_photo.jpg",
"filename": "1723567623_user_photo.jpg"
}- Method: POST
- URL:
http://localhost:8000/reports/upload - Headers:
Authorization: Bearer <your_token> - Body:
- Type: form-data
- Key:
file(Type: File) - Value: Select an image file
- Method: POST
- URL:
http://localhost:8000/reports/ - Headers:
Authorization: Bearer <your_token>Content-Type: application/json
- Body (JSON):
{
"student_id": "student123",
"waste_type": "recyclable_plastic",
"location": {
"type": "Point",
"coordinates": [-74.006, 40.7128]
},
"image_url": "/static/images/your_uploaded_image.jpg",
"safe": true,
"urban_area": true
}- Method: POST
- URL:
http://localhost:8000/reports/with-image - Headers:
Authorization: Bearer <your_token> - Body:
- Type: form-data
- Add these fields:
student_id: student123waste_type: recyclable_plasticlongitude: -74.006latitude: 40.7128safe: trueurban_area: truefile: [Select image file]
GET /reports/GET /reports/{report_id}GET /reports/?waste_type=recyclable_plastic&status=new- ✅ JPEG (.jpg, .jpeg)
- ✅ PNG (.png)
- ✅ WebP (.webp)
- ✅ GIF (.gif)
Images are automatically renamed to: {timestamp}_{user}_{original_name}
Example: 1723567623_testuser_waste_photo.jpg
- Images stored in:
backend/storage/images/ - Accessible via:
http://localhost:8000/static/images/{filename}
- Use cloud storage (AWS S3, Google Cloud Storage)
- Set up CDN for faster image delivery
- Implement image compression/resizing
- ✅ All upload endpoints require valid JWT token
- ✅ Users can only modify their own reports (unless admin/staff)
- ✅ File type validation (only images allowed)
- ✅ Filename sanitization
- ✅ User identification in filename
- Students: Can upload images to their own reports
- Staff/Admin: Can upload images to any report
- Always upload image first, then create report
- Handle upload progress for better UX
- Validate file size before upload (recommend < 5MB)
- Show image preview after upload
- Provide fallback if image upload fails
- Use single-step endpoint
/reports/with-imagefor simplicity - Compress images before upload
- Handle offline scenarios (save to upload later)
try {
const uploadResponse = await uploadImage(file);
const reportResponse = await createReport({
...reportData,
image_url: uploadResponse.url
});
} catch (error) {
// Handle upload or report creation failure
console.error('Failed to create report with image:', error);
}// Complete workflow for creating report with image
async function createReportWithImage(reportData, imageFile) {
try {
// Step 1: Upload image
const formData = new FormData();
formData.append('file', imageFile);
const uploadResponse = await fetch('/reports/upload', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
},
body: formData
});
const uploadResult = await uploadResponse.json();
// Step 2: Create report with image URL
const reportResponse = await fetch('/reports/', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
...reportData,
image_url: uploadResult.url
})
});
const report = await reportResponse.json();
console.log('Report created with image:', report);
return report;
} catch (error) {
console.error('Failed to create report with image:', error);
throw error;
}
}Your image linking functionality is now complete! 🎉