feat(03-01): add API endpoints for serving images
- Add GET /api/images/[id] for original images - Add GET /api/images/[id]/thumbnail for thumbnails - Both endpoints return 404 for missing images - Immutable cache headers for CDN optimization
This commit is contained in:
40
src/routes/api/images/[id]/+server.ts
Normal file
40
src/routes/api/images/[id]/+server.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import { imageRepository } from '$lib/server/db/repository';
|
||||||
|
import { getOriginalPath } from '$lib/server/images/storage';
|
||||||
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
|
const MIME_TYPES: Record<string, string> = {
|
||||||
|
jpg: 'image/jpeg',
|
||||||
|
jpeg: 'image/jpeg',
|
||||||
|
png: 'image/png',
|
||||||
|
gif: 'image/gif',
|
||||||
|
webp: 'image/webp',
|
||||||
|
heic: 'image/heic',
|
||||||
|
heif: 'image/heif'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GET: RequestHandler = async ({ params }) => {
|
||||||
|
const { id } = params;
|
||||||
|
|
||||||
|
const image = imageRepository.getById(id);
|
||||||
|
if (!image) {
|
||||||
|
error(404, 'Image not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const path = getOriginalPath(id, image.ext);
|
||||||
|
const buffer = await readFile(path);
|
||||||
|
const mimeType = MIME_TYPES[image.ext.toLowerCase()] || 'application/octet-stream';
|
||||||
|
|
||||||
|
return new Response(buffer, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': mimeType,
|
||||||
|
'Content-Length': buffer.length.toString(),
|
||||||
|
'Cache-Control': 'public, max-age=31536000, immutable'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
error(404, 'Image file not found');
|
||||||
|
}
|
||||||
|
};
|
||||||
29
src/routes/api/images/[id]/thumbnail/+server.ts
Normal file
29
src/routes/api/images/[id]/thumbnail/+server.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import { imageRepository } from '$lib/server/db/repository';
|
||||||
|
import { getThumbnailPath } from '$lib/server/images/storage';
|
||||||
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
|
export const GET: RequestHandler = async ({ params }) => {
|
||||||
|
const { id } = params;
|
||||||
|
|
||||||
|
const image = imageRepository.getById(id);
|
||||||
|
if (!image) {
|
||||||
|
error(404, 'Image not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const path = getThumbnailPath(id);
|
||||||
|
const buffer = await readFile(path);
|
||||||
|
|
||||||
|
return new Response(buffer, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'image/jpeg',
|
||||||
|
'Content-Length': buffer.length.toString(),
|
||||||
|
'Cache-Control': 'public, max-age=31536000, immutable'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
error(404, 'Thumbnail not found');
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user