Media APIs

Image upload and management

Media APIs

Endpoints for uploading and managing images in R2 storage.

Base URL: https://ycwadelaide.adenmgb.com

Authentication: All endpoints require Authorization: Bearer <token> header.

POST /api/staff/upload/image

Upload an image file to R2 storage and get back a URL for use in content.

Headers:

Authorization: Bearer <token>
Content-Type: multipart/form-data

Request Body (FormData):

file: <File object>

Success Response (200 OK):

{
  "url": "/api/images/images/1703123456789-abc123def456.jpg",
  "key": "images/1703123456789-abc123def456.jpg",
  "filename": "1703123456789-abc123def456.jpg",
  "duplicate": false
}

If duplicate image detected:

{
  "url": "/api/images/images/existing-image.jpg",
  "key": "images/existing-image.jpg",
  "filename": "existing-image.jpg",
  "duplicate": true
}

Error Responses:

  • 400 Bad Request - No file provided
{
  "error": "No file provided"
}
  • 400 Bad Request - Invalid file type
{
  "error": "Invalid file type. Only images are allowed."
}
  • 401 Unauthorized - Not authenticated
{
  "error": "Unauthorized"
}
  • 500 Internal Server Error - Upload failed
{
  "error": "Failed to upload image"
}

Important Notes:

  • Allowed file types: image/jpeg, image/jpg, image/png, image/webp, image/gif
  • Files are automatically deduplicated by SHA-256 hash
  • Returns existing URL if duplicate detected (saves storage space)
  • Images are stored in R2 bucket with CDN access
  • Use the returned url in imageUrl or coverImageUrl fields
  • Filename is auto-generated with timestamp and random string

Example Request (JavaScript/Fetch):

const formData = new FormData()
formData.append('file', fileInput.files[0])

const response = await fetch('/api/staff/upload/image', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`
  },
  body: formData
})

const result = await response.json()
console.log('Image URL:', result.url)

Example Request (cURL):

curl -X POST https://ycwadelaide.adenmgb.com/api/staff/upload/image \
  -H "Authorization: Bearer <token>" \
  -F "file=@/path/to/image.jpg"

GET /api/staff/images

List all uploaded images from R2 storage for selection/reuse.

Headers:

Authorization: Bearer <token>

Success Response (200 OK):

[
  {
    "key": "images/1703123456789-abc123.jpg",
    "url": "/api/images/images/1703123456789-abc123.jpg",
    "filename": "1703123456789-abc123.jpg",
    "size": 245678,
    "uploadedAt": "2024-12-15T10:30:00.000Z"
  }
]

Error Responses:

  • 401 Unauthorized - Not authenticated
{
  "error": "Unauthorized"
}
  • 500 Internal Server Error - Failed to list images
{
  "error": "Failed to list images"
}

Use Cases:

  • Browse uploaded images
  • Select existing images for content
  • Image library/gallery view
  • Reuse previously uploaded images
  • Check image metadata (size, upload date)

Notes:

  • Returns all images in R2 bucket
  • Results include metadata (size in bytes, upload date)
  • Use url field to reference images in content
  • Consider implementing pagination for large image libraries
  • Results are ordered by upload date (newest first)

Example - Use image URL in content:

// After selecting image from library
const selectedImage = {
  url: "/api/images/images/1703123456789-abc123.jpg"
}

// Use in action/news/event creation
const actionData = {
  title: "New Action",
  coverImageUrl: selectedImage.url,
  // ... other fields
}

Image Serving

Images are served via the /api/images/ path:

GET /api/images/images/filename.jpg

Notes:

  • Images are served directly from R2 bucket
  • CDN caching enabled for performance
  • No authentication required for image URLs
  • Images are publicly accessible once uploaded

Best Practices

  1. Compress Images - Compress images before upload for better performance
  2. Validate Client-Side - Check file type and size before upload
  3. Show Progress - Display upload progress indicator
  4. Handle Duplicates - Check duplicate flag and inform user
  5. Use Appropriate Sizes - Upload appropriately sized images:
    • Featured images: 1200x630px
    • Content images: 800-1200px wide
    • Thumbnails: 400x400px