Media Handling
Trokky provides a complete media management system for handling images, files, and other assets.
Overview
Section titled “Overview”The media system supports:
- Image uploads with automatic optimization
- Multiple image variants (thumbnails, responsive sizes)
- File uploads (PDFs, documents, etc.)
- Media library with search and filtering
- CDN-ready URL generation
Quick Setup
Section titled “Quick Setup”Basic Configuration
Section titled “Basic Configuration”const trokky = await TrokkyExpress.create({ media: { uploadDir: './uploads', maxFileSize: 10 * 1024 * 1024, // 10MB allowedTypes: ['image/*', 'application/pdf'], }, // ...});With Image Processing
Section titled “With Image Processing”Install Sharp for image optimization:
npm install sharpconst trokky = await TrokkyExpress.create({ media: { uploadDir: './uploads', processor: 'sharp', variants: [ { name: 'thumb', width: 200, height: 200, fit: 'cover' }, { name: 'medium', width: 800 }, { name: 'large', width: 1600 }, ], }, // ...});Configuration Options
Section titled “Configuration Options”Full Media Configuration
Section titled “Full Media Configuration”const trokky = await TrokkyExpress.create({ media: { // Storage location uploadDir: './uploads',
// File limits maxFileSize: 10 * 1024 * 1024, // 10MB maxFiles: 10, // Per request
// Allowed MIME types allowedTypes: [ 'image/jpeg', 'image/png', 'image/webp', 'image/gif', 'application/pdf', 'video/mp4', ],
// Image processing processor: 'sharp', quality: 80, // JPEG/WebP quality format: 'webp', // Convert images to format
// Image variants variants: [ { name: 'thumb', width: 200, height: 200, fit: 'cover' }, { name: 'small', width: 400 }, { name: 'medium', width: 800 }, { name: 'large', width: 1600 }, { name: 'og', width: 1200, height: 630, fit: 'cover' }, ],
// URL generation baseUrl: 'https://cdn.example.com', pathPrefix: '/media',
// Metadata extraction extractMetadata: true,
// Cleanup removeOriginal: false, // Keep original file cleanupOrphans: true, // Remove unused files }, // ...});Image Variants
Section titled “Image Variants”Variant Options
Section titled “Variant Options”| Option | Type | Description |
|---|---|---|
name | string | Variant identifier |
width | number | Maximum width in pixels |
height | number | Maximum height in pixels |
fit | string | Resize strategy: cover, contain, fill, inside, outside |
format | string | Output format: jpeg, png, webp, avif |
quality | number | Output quality (1-100) |
Fit Modes
Section titled “Fit Modes”variants: [ // Crop to exact dimensions { name: 'square', width: 500, height: 500, fit: 'cover' },
// Fit within dimensions (may have whitespace) { name: 'contain', width: 800, height: 600, fit: 'contain' },
// Stretch to fill (distorts aspect ratio) { name: 'fill', width: 400, height: 300, fit: 'fill' },
// Resize to fit inside, preserving aspect ratio { name: 'inside', width: 1200, height: 800, fit: 'inside' },]API Endpoints
Section titled “API Endpoints”Upload Media
Section titled “Upload Media”POST /api/mediaContent-Type: multipart/form-data
file: (binary)alt: "Image description"Response:
{ "_id": "media-abc123", "filename": "photo.jpg", "originalFilename": "IMG_1234.jpg", "mimeType": "image/jpeg", "size": 245678, "width": 1920, "height": 1080, "alt": "Image description", "variants": { "thumb": "/media/photo-abc123-thumb.webp", "medium": "/media/photo-abc123-medium.webp", "large": "/media/photo-abc123-large.webp" }, "url": "/media/photo-abc123.jpg", "createdAt": "2024-01-15T10:00:00Z"}List Media
Section titled “List Media”GET /api/media?type=image&limit=20&offset=0Get Media
Section titled “Get Media”GET /api/media/{id}Update Media Metadata
Section titled “Update Media Metadata”PATCH /api/media/{id}Content-Type: application/json
{ "alt": "Updated description", "title": "Photo title"}Delete Media
Section titled “Delete Media”DELETE /api/media/{id}Using Media in Schemas
Section titled “Using Media in Schemas”Media Field
Section titled “Media Field”{ name: 'featuredImage', type: 'media', title: 'Featured Image', options: { accept: ['image/*'], // Allowed types maxSize: 5 * 1024 * 1024, // 5MB showVariants: true, // Show variant selector showMetadata: true, // Show metadata editor requireAlt: true, // Require alt text },}Document with Media
Section titled “Document with Media”{ "_id": "post-abc123", "_type": "post", "title": "My Post", "featuredImage": { "_type": "media", "_ref": "media-xyz789", "alt": "Post cover image" }}Fetching with Media
Section titled “Fetching with Media”When querying documents, media references are expanded:
GET /api/documents/post/abc123?expand=featuredImage{ "_id": "post-abc123", "title": "My Post", "featuredImage": { "_id": "media-xyz789", "url": "/media/photo-xyz789.jpg", "alt": "Post cover image", "variants": { "thumb": "/media/photo-xyz789-thumb.webp", "medium": "/media/photo-xyz789-medium.webp" } }}Client SDK Usage
Section titled “Client SDK Usage”Upload
Section titled “Upload”import { createClient } from '@trokky/client';
const client = createClient({ apiUrl: 'http://localhost:3000/api' });
// Upload fileconst file = document.querySelector('input[type="file"]').files[0];const media = await client.media.upload(file, { alt: 'Image description',});
console.log(media.url);console.log(media.variants.thumb);List and Filter
Section titled “List and Filter”// List all imagesconst images = await client.media.list({ type: 'image', limit: 20,});
// Search by filenameconst results = await client.media.list({ search: 'hero',});Storage Integration
Section titled “Storage Integration”Filesystem
Section titled “Filesystem”Media stored in configured directory:
uploads/├── images/│ ├── photo-abc123.jpg # Original│ ├── photo-abc123-thumb.webp # Variant│ ├── photo-abc123-medium.webp # Variant│ └── photo-abc123-large.webp # Variant├── files/│ └── document-def456.pdf└── .metadata/ ├── photo-abc123.json └── document-def456.jsonmedia: { storage: 's3', bucket: 'my-media-bucket', prefix: 'uploads/', cdnUrl: 'https://cdn.example.com',}Cloudflare R2
Section titled “Cloudflare R2”media: { storage: 'cloudflare', r2Bucket: env.R2_BUCKET, publicUrl: 'https://media.example.com',}Performance Optimization
Section titled “Performance Optimization”Lazy Variant Generation
Section titled “Lazy Variant Generation”Generate variants on-demand instead of at upload:
media: { lazyVariants: true, variantCacheTtl: 86400, // 24 hours}CDN Integration
Section titled “CDN Integration”media: { baseUrl: 'https://cdn.example.com',
// Custom URL transformation transformUrl: (path, variant) => { return `https://cdn.example.com/${variant}/${path}`; },}Responsive Images
Section titled “Responsive Images”Generate srcset for responsive images:
// In frontendconst srcset = Object.entries(media.variants) .map(([name, url]) => { const width = { thumb: 200, small: 400, medium: 800, large: 1600 }[name]; return `${url} ${width}w`; }) .join(', ');
// <img srcset="..." sizes="(max-width: 600px) 400px, 800px" />Studio Media Library
Section titled “Studio Media Library”The Studio includes a built-in media library with:
- Grid/list view toggle
- Type filtering (images, documents, etc.)
- Search by filename
- Drag-and-drop upload
- Bulk selection and deletion
- Inline metadata editing
Customizing the Library
Section titled “Customizing the Library”studio: { media: { defaultView: 'grid', itemsPerPage: 24, showUploadZone: true, allowBulkDelete: true, },}Next Steps
Section titled “Next Steps”- Studio Customization - Customize the admin interface
- Deployment - Deploy to production
- HTTP API Reference - Complete API documentation