Skip to content

Commit c72bbf1

Browse files
wontoryclaude
andcommitted
feat(web): add badge API route
Add GET endpoint for badge SVG generation with hex color validation, text length limit, and cache-control headers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b33b158 commit c72bbf1

1 file changed

Lines changed: 38 additions & 0 deletions

File tree

apps/web/app/api/badge/route.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { generateBadgeSvg } from '@tech-stack/badge'
2+
import type { NextRequest } from 'next/server'
3+
import { resolveSimpleIcon } from '#utils/simple-icon'
4+
5+
const HEX_COLOR = /^[0-9a-fA-F]{3,8}$/
6+
7+
export async function GET(request: NextRequest) {
8+
const { searchParams } = request.nextUrl
9+
const slug = searchParams.get('slug') || ''
10+
const text = (searchParams.get('text') || '').slice(0, 100)
11+
const highlight = searchParams.get('highlight') === 'true'
12+
const rawTextColor = searchParams.get('textColor') || ''
13+
const rawIconColor = searchParams.get('iconColor') || ''
14+
const rawBgColor = searchParams.get('bgColor') || ''
15+
const textColor = HEX_COLOR.test(rawTextColor) ? rawTextColor : ''
16+
const iconColor = HEX_COLOR.test(rawIconColor) ? rawIconColor : ''
17+
const bgColor = HEX_COLOR.test(rawBgColor) ? rawBgColor : ''
18+
19+
const icon = slug ? resolveSimpleIcon(slug) : undefined
20+
21+
if (slug && !icon) {
22+
return Response.json(
23+
{ error: `Icon with slug "${slug}" not found` },
24+
{ status: 404 },
25+
)
26+
}
27+
28+
const badgeSvg = generateBadgeSvg(
29+
{ slug, text, highlight, textColor, iconColor, bgColor },
30+
icon ?? null,
31+
)
32+
return new Response(badgeSvg, {
33+
headers: {
34+
'content-type': 'image/svg+xml',
35+
'cache-control': 'public, max-age=3600, s-maxage=3600',
36+
},
37+
})
38+
}

0 commit comments

Comments
 (0)