Show GN: routar - 백엔드 스펙 없이 프론트에서 API 스키마를 간편하게 관리하는 타입세이프 HTTP 클라이언트를 ...

3 hours ago 4

안녕하세요, 사이드 프로젝트로 routar라는 라이브러리를 만들어서 공유합니다. 부족한 부분이 많기에 피드백 많이 부탁드립니다. 제작 계기 OpenAPI 스펙도 없고 백엔드와 계약을 공유하기도 애매한 REST 프로젝트에서, 프론트가 API 스키마를 직접 정의해야 하는 상황이 많았습니다. Zodios와 ts-rest에서 아이디어를 얻었는데 둘 다 제 상황엔 아쉬운 지점이 있었습니다. Zodios는 axios에 묶여 있는데다가 요청 파라미터가 path/query/body 구분 없이 하나의 배열이라 값이 어디서 오는지 코드만 보고 알기 어려웠고, ts-rest는 contract를 백엔드와 공유하는 걸 전제로 하는데, 때문에 contract의 API가 너무 장황하기도 하고, 특히 contract가 전송 계층(fetch/axios/ky)와 결합되어 재활용이 어렵다는 단점도 크게 다가왔습니다. 그래서 routar에서 request는 { path, query, body }로 명확히 나누고(flatten 옵션도 제공), 전송 계층은 독립된 executor로 완전히 분리했습니다. @routar/core는 zero-dependency이고 axios/ky는 각각 별도 패키지라서, 전송 계층을 바꿔도 라우터·검증 로직에는 어떤 의존성도 끼지 않습니다. 백엔드 소유 여부와 무관하게 프론트 혼자 쓸 수 있는 도구를 만들고 싶었습니다. 기능 소개 const todoRouter = defineRouter('/todos', { getDetail: endpoint({ method: 'GET', path: '/:id', request: { path: z.object({ id: z.number() }) }, response: TodoSchema, }), create: endpoint({ method: 'POST', path: '/', request: { body: z.object({ title: z.string() }) }, response: TodoSchema, }), }); const todoApi = createApi(createFetchExecutor('https://api.example.com'), todoRouter); const todo = await todoApi.getDetail({ path: { id: 1 } }); // GET, path param const next = await todoApi.create({ body: { ...

Read Entire Article