65 lines
1.7 KiB
TypeScript
65 lines
1.7 KiB
TypeScript
/**
|
|
* MediaAdapter
|
|
*
|
|
* Handles HTTP operations for media assets.
|
|
* This is where external API calls belong.
|
|
*/
|
|
|
|
import { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';
|
|
import { Result } from '@/lib/contracts/Result';
|
|
import { DomainError } from '@/lib/contracts/services/Service';
|
|
import { MediaBinaryDTO } from '@/lib/types/MediaBinaryDTO';
|
|
|
|
// TODO why is this an adapter?
|
|
|
|
/**
|
|
* MediaAdapter
|
|
*
|
|
* Handles binary media fetching from the API.
|
|
* All HTTP calls are isolated here.
|
|
*/
|
|
export class MediaAdapter {
|
|
private baseUrl: string;
|
|
|
|
constructor() {
|
|
this.baseUrl = getWebsiteApiBaseUrl();
|
|
}
|
|
|
|
/**
|
|
* Fetch binary media from API
|
|
*
|
|
* @param mediaPath - API path to media resource
|
|
* @returns Result with MediaBinaryDTO on success, DomainError on failure
|
|
*/
|
|
async fetchMedia(mediaPath: string): Promise<Result<MediaBinaryDTO, DomainError>> {
|
|
try {
|
|
const response = await fetch(`${this.baseUrl}${mediaPath}`, {
|
|
method: 'GET',
|
|
});
|
|
|
|
if (!response.ok) {
|
|
if (response.status === 404) {
|
|
return Result.err({
|
|
type: 'notFound',
|
|
message: `Media not found: ${mediaPath}`
|
|
});
|
|
}
|
|
return Result.err({
|
|
type: 'serverError',
|
|
message: `HTTP ${response.status}: ${response.statusText}`
|
|
});
|
|
}
|
|
|
|
const buffer = await response.arrayBuffer();
|
|
const contentType = response.headers.get('content-type') || 'image/svg+xml';
|
|
|
|
return Result.ok({ buffer, contentType });
|
|
} catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
return Result.err({
|
|
type: 'networkError',
|
|
message: `Failed to fetch media: ${errorMessage}`
|
|
});
|
|
}
|
|
}
|
|
} |