자동차 사진을 하나도 저장하지 않고 보여주는 방법
Source: Dev.to
번역할 텍스트가 제공되지 않았습니다. 번역이 필요한 전체 내용을 알려주시면 도와드리겠습니다.
문제
대부분의 자동차 데이터 API는 비용이 많이 들거나 라이선스 계약이 필요하거나, 인기 있는 시장만을 다룹니다. 저는 Renault Clio, SEAT Ibiza, Fiat Punto와 같은 모델을 가지고 있는데, 이는 미국 중심의 유료 API에서는 아예 나타나지 않을 수도 있는 기본적인 유럽 차종입니다.
소스를 찾았다 하더라도 수천 개의 이미지를 R2 또는 S3에 호스팅하려면 다음과 같은 문제가 발생합니다:
- 이미지를 다운로드하고 저장하는 파이프라인
- 카탈로그 규모에 따라 증가하는 저장 비용
- 이미지가 오래되었을 때의 유지보수
더 나은 방법이 필요했습니다.
해결책: Wikimedia Commons
Wikimedia Commons는 수백만 개의 이미지가 있는 무료 미디어 저장소이며, 그 중에는 방대한 자동차 사진 컬렉션도 포함되어 있습니다. 모든 이미지가 Creative Commons 라이선스 하에 제공됩니다. 또한 공개 JSON API를 제공하는데, 인증이나 API 키가 필요 없으며 요청당 비용도 없습니다.
핵심: Commons에서 "BMW 3 Series"를 검색하고 첫 번째 이미지 결과를 가져옵니다. 끝.
const url =
"https://commons.wikimedia.org/w/api.php" +
"?action=query" +
"&generator=search" +
"&gsrsearch=" + encodeURIComponent(`${brand} ${model}`) +
"&gsrnamespace=6" + // namespace 6 = File/Image namespace only
"&prop=imageinfo" +
"&iiprop=url" +
"&format=json" +
"&origin=*"; // enables CORS for browser requests
const response = await fetch(url);
const data = await response.json();
const pages = data.query?.pages;
const firstPage = Object.values(pages)[0];
const imageUrl = firstPage?.imageinfo?.[0]?.url;
그게 전부입니다. Wikimedia CDN에 호스팅된 고해상도 이미지의 직접 URL을 얻을 수 있습니다. 내 서버는 이를 전혀 건드리지 않죠.
Svelte 컴포넌트
로드, 오류, 폴백을 깔끔하게 처리하도록 VehicleImage 컴포넌트에 래핑했습니다:
<script lang="ts">
import { onMount } from 'svelte';
export let brand: string;
export let model: string;
export let year: number | null = null;
let imageUrl: string | null = null;
let loading = true;
let error = false;
$: searchQuery = year ? `${brand} ${model} ${year}` : `${brand} ${model}`;
async function loadImage() {
loading = true;
error = false;
try {
const url =
'https://commons.wikimedia.org/w/api.php' +
'?action=query&generator=search' +
'&gsrsearch=' + encodeURIComponent(searchQuery) +
'&gsrnamespace=6&prop=imageinfo&iiprop=url&format=json&origin=*';
const res = await fetch(url);
const data = await res.json();
const pages = data.query?.pages;
const first = Object.values(pages ?? {})[0] as any;
imageUrl = first?.imageinfo?.[0]?.url ?? null;
if (!imageUrl) error = true;
} catch {
error = true;
} finally {
loading = false;
}
}
onMount(loadImage);
</script>
{#if loading}
<p>Loading image…</p>
{:else if error || !imageUrl}
<p>Image not available.</p>
{:else}
<img src={imageUrl} alt="{brand} {model}" />
{/if}
핵심 인사이트: fetch는 브라우저에서 실행되며 서버에서는 실행되지 않습니다. 이는:
- 서버 부하 0
- 저장 비용 0
- 이미지가 Wikimedia 전역 CDN을 통해 직접 사용자에게 제공
- Wikimedia가 다운되면 우아한 폴백을 보여줌 — 오류가 발생하지 않음
왜 클라이언트‑사이드인가?
나는 Cloudflare Workers에서 실행 중인데, 무료 티어에서는 일부 작업에 10 ms CPU 제한이 있습니다. 매 페이지 로드마다 서버‑사이드로 Wikimedia에 fetch를 하면 낭비가 되고 타임아웃에 걸릴 수 있습니다. onMount로 클라이언트‑사이드에서 수행하면 SSR 콘텐츠와 함께 페이지가 즉시 로드되고, 이미지가 “팝업”되는 형태가 되어 인지된 성능이 크게 향상됩니다.
주의점: 첫 번째 결과가 항상 완벽하지는 않음
Wikimedia 검색의 첫 번째 결과가 정확히 해당 트림의 사진이라고 보장할 수는 없습니다. 경우에 따라:
- 약간 다른 연도의 사진
- 공장 또는 모터쇼 이미지
- 가끔은 실내 사진
그래서 나는 모든 6개 언어에 다음과 같은 면책 조항을 추가했습니다:
“이미지는 예시용이며 설명된 모델을 정확히 나타내지 않을 수 있습니다.”
커뮤니티 리뷰 플랫폼에서는 이것이 충분히 허용됩니다. 사용자는 우리에게서 차를 구매하는 것이 아니라 리뷰를 읽는 것이므로, 빈 박스보다 대략적인 이미지가 훨씬 낫습니다.
법적 측면: 출처 표시가 중요합니다
쉽게 놓치기 쉬운 점: 위키미디어 커먼즈 이미지가 기본적으로 퍼블릭 도메인이 아닙니다. 대부분은 크리에이티브 커먼즈 라이선스가 적용되며, 실제로 지켜야 할 요구사항이 있습니다:
| 라이선스 | 요구사항 |
|---|---|
| CC BY | 저자에게 크레딧 표시 |
| CC BY‑SA | 저자에게 크레딧 표시 + 동일 라이선스로 2차 저작물 공유 |
| Public Domain | 제한 없음 — 자유롭게 사용 가능 |
URL만 가져와서 이미지에 출처 표시 없이 표시하면, 위키미디어가 기술적으로 핫링크를 차단하지 않더라도 라이선스를 위반할 수 있습니다.
출처 메타데이터 가져오기
좋은 소식: 이미지 URL을 반환하는 동일한 API 호출에 extmetadata를 추가하면 필요한 모든 정보를 얻을 수 있습니다. iiprop 매개변수에 extmetadata를 포함하세요:
const url =
"https://commons.wikimedia.org/w/api.php" +
"?action=query" +
"&generator=search" +
"&gsrsearch=" + encodeURIComponent(searchQuery) +
"&gsrnamespace=6" +
"&prop=imageinfo" +
"&iiprop=url|extmetadata" + // URL과 메타데이터 요청
"&format=json" +
"&origin=*";
응답의 extmetadata 필드에는 라이선스 이름, 저자, 출처 URL 등 여러 정보가 들어 있습니다. 해당 값을 추출해 이미지 아래에 적절한 출처 표시 줄을 렌더링하면 크리에이티브 커먼즈 요구사항을 충족할 수 있습니다.
이미지 배너

<div class="attribution">
Via Wikimedia Commons
{#if author} · {author}{/if}
{#if licenseShortName}
· {licenseShortName}
{/if}
</div>
이 코드는 다음과 같은 형태로 출력됩니다:
Via Wikimedia Commons · Vauxford · CC BY‑SA 4.0
이는 라이선스가 요구하는 정확한 형태이며, 페이지의 신뢰성을 높여 줍니다.
핫링크는 어떻게 되나요?
위키미디어는 CDN(upload.wikimedia.org)을 통한 외부 이미지 삽입을 명시적으로 허용합니다. 차단하지도 않습니다. 하지만 그들의 이용 약관과 개별 파일 라이선스는 여전히 적용됩니다. 출처 표시 없이 이미지를 제공하는 것은 기술적으로는 작동하더라도 라이선스 위반이 됩니다.
올바른 사고 모델: 핫링크는 허용되지만, 출처 표시는 필수입니다.
The Result
-
0 images stored in my database or on any storage bucket
-
0 API keys to manage or rotate
-
0 monthly costs for image serving
-
Works for every European car brand that has any Wikipedia/Commons presence
-
Graceful fallback for truly obscure models
-
Full legal compliance with a single extra API field and four lines of HTML
The entire solution is ~50 lines of Svelte. Sometimes the best engineering is finding the data that already exists, pointing at it — and reading the license.