All files / src/pages/api image.ts

100% Statements 50/50
83.33% Branches 10/12
100% Functions 1/1
100% Lines 50/50

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67      1x 1x 1x   1x 5x 5x 5x   5x 1x 1x 1x 1x   4x   5x 1x 1x 1x 1x   5x 5x     2x 5x   5x     5x   5x 5x 1x 5x 1x 1x 1x 1x 1x 1x 1x 1x     1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 5x  
import type { APIRoute } from 'astro';
 
// Constants
import { ERROR_MESSAGES } from '@/constants/messages';
import { STATUS_CODE, STATUS_MESSAGES } from '@shared/constants';
import { ENV } from '@/constants/env';
 
export const GET: APIRoute = async ({ request }) => {
  try {
    const url = new URL(request.url);
    const imageUrl = url.searchParams.get('url');
 
    if (!imageUrl) {
      return new Response(ERROR_MESSAGES.MISSING_URL, {
        status: STATUS_CODE.BAD_REQUEST,
      });
    }
 
    const response = await fetch(imageUrl);
 
    if (!response.ok) {
      return new Response(ERROR_MESSAGES.FETCH_FAILED(response.status), {
        status: response.status,
      });
    }
 
    const contentType = response.headers.get('content-type') || 'image/jpeg';
    const buffer = await response.arrayBuffer();
 
    // Use Last-Modified from backend response if available, otherwise generate one
    const lastModified =
      response.headers.get('last-modified') || new Date().toUTCString();
    // Check If-Modified-Since from browser to support 304 Not Modified
    const ifModifiedSince = request.headers.get('if-modified-since');
    // cacheMaxAge = the number of seconds that browsers and CDNs should cache the image.
    // otherwise it defaults to 604800 seconds (7 days).
    const cacheMaxAge = ENV.IMAGE_CACHE_MAX_AGE ?? 604800;
 
    if (
      ifModifiedSince &&
      new Date(ifModifiedSince) >= new Date(lastModified)
    ) {
      return new Response(null, {
        status: STATUS_CODE.NOT_MODIFIED,
        headers: {
          'Cache-Control': `public, max-age=${cacheMaxAge}, immutable`,
          'Last-Modified': lastModified,
        },
      });
    }
 
    // Return the image buffer with cache headers
    return new Response(buffer, {
      status: STATUS_CODE.OK,
      headers: {
        'Content-Type': contentType,
        'Cache-Control': `public, max-age=${cacheMaxAge}, immutable`,
        'Last-Modified': lastModified,
      },
    });
  } catch (err) {
    return new Response(STATUS_MESSAGES[STATUS_CODE.INTERNAL_SERVER_ERROR], {
      status: STATUS_CODE.INTERNAL_SERVER_ERROR,
    });
  }
};