💻 Dev

🛠️ 처음부터 만드는 URL Router — Express-style 패턴 매칭 25줄 구현

왜 직접 만드나?


Express, Hono, Fastify 전부 내부에 URL 패턴 매칭 라우터가 있다.
`:id` → 정규식 변환, 파라미터 추출 — 이 핵심 로직을 25줄로 구현한다.

핵심 구현


```typescript
type Handler = (params: Record) => void;
type Route = { pattern: RegExp; keys: string[]; handler: Handler };
class Router {
private routes: Route[] = [];
add(path: string, handler: Handler) {
const keys: string[] = [];
const pattern = new RegExp(
'^' + path.replace(/:([\w]+)/g, (_, k) => {
keys.push(k);
return '([^/]+)';
}) + '$'
);
this.routes.push({ pattern, keys, handler });
}
match(path: string) {
for (const { pattern, keys, handler } of this.routes) {
const m = path.match(pattern);
if (!m) continue;
const params: Record = {};
keys.forEach((k, i) => params[k] = m[i + 1]);
return { handler, params };
}
return null;
}
}
```

사용 예시


```typescript
const router = new Router();
router.add('/users/:id', (p) => console.log(`User ${p.id}`));
router.add('/posts/:postId/comments/:commentId', (p) => {
console.log(`Post ${p.postId}, Comment ${p.commentId}`);
});
router.match('/users/42');
// → { handler: fn, params: { id: '42' } }
router.match('/posts/7/comments/99');
// → { params: { postId: '7', commentId: '99' } }
router.match('/unknown'); // → null
```

핵심 원리


| 단계 | 입력 | 출력 |
|------|------|------|
| 등록 | `/users/:id` | `^/users/([^/]+)$` + keys=`['id']` |
| 매칭 | `/users/42` | match → `['42']` |
| 추출 | keys + groups | `{ id: '42' }` |
`:param` → `([^/]+)` 변환이 전부다. 캡처 그룹 순서와 keys 배열이 1:1 대응한다.

확장 포인트


  • 와일드카드: `/api/*` → `(.*)` 변환 추가

  • HTTP 메서드: `add('GET', path, handler)` 필터링

  • 미들웨어: handler를 배열로 바꿔 `next()` 체인

  • 우선순위: 정적 경로(`/users/me`)를 동적(`:id`)보다 먼저 매칭

  • > Express의 `path-to-regexp`, Hono의 `URLPattern` — 프로덕션 라우터도 이 원리 위에 최적화를 쌓은 것이다.
    💬 0
    👁 0 views

    Comments (0)

    💬

    No comments yet.

    Be the first to comment!