깃허브 리드미에 velog에 작성했던 글을 몇 개 추려서 리스트로 보여주면 좋을거 같다는 생각이 들었습니다.
그래서, velog의 openAPI나 다른 사람이 구현한 API 중에서 찾아봤는데
슬프게도 없었습니다.
마침 무료로 사용하고 있는 서버도 있어서 이 서버를 이용해서
카드 형식으로 보여주면 좋을 거 같다는 생각이 들어서
개발하기로 했습니다.
velog의 제목과 URL을 5개 받아와서 카드 형식으로 보여준다.
우선 velog 전체 글을 가져오는 것부터 시작해봤습니다.
하지만 슬프게도 velog에는 API 명세서가 없어서 API를 확인할 수 없었습니다.
그래서 RSS에서 직접 XML을 불러오는 방법을 선택했습니다.
구글링을 하니 https://v2.velog.io/rss/(벨로그 id)를 하면 velog의 RSS를 얻을 수 있는 것을 확인했습니다.
그래서 postman으로 확인해봤습니다.
여기서 제가 필요한 것은 게시물 제목과 링크라서
게시물이 존재하는 헤더를 찾고 그 안에서 또 제목과 링크가 들어있는 헤더를 찾았습니다.
찾아보니 게시물은 < item >< /item > 안에 있고,
제목과 링크는 각각 게시물 안에 < title >< /title >, < link >< /link >로 있었습니다.
전체 데이터를 가지고 오는 방법을 찾았으므로 이제 여기서 최신 5개의 데이터를 가져오고,
여기서 제목과 링크만을 가져오는 API를 구현하는 쪽으로 목표를 잡았습니다.
그래서 우선 데이터를 보기 좋게 하기 위해 XML을 JSON으로 바꾸고,
우선 rss, chanel, item을 건너가서 게시물만을 불러왔습니다.
next.js로 SSR한 서버라서 코드는 js로 구현했습니다.
import { NextResponse } from "next/server";
import { parseStringPromise } from "xml2js";
export async function GET() {
try {
const res = await fetch("https://v2.velog.io/rss/hwangrock1220");
const xml = await res.text();
const data = await parseStringPromise(xml, { explicitArray: false });
const posts = data.rss.channel.item;
return NextResponse.json(posts, { status: 200 });
} catch (err: any) {
return NextResponse.json({ error: err.message }, { status: 500 });
}
}
이렇게 하면,
게시물 데이터만 잘 온 것을 볼 수 있습니다.
이제 여기서 제목하고 링크만을 찾고 있으므로 title, link만으로 한정시켜서 불러왔습니다.
const result=posts.map((post:any) => ({
title:post.title,
link:post.link,
}));
위에서 이것만 추가하고 반환 json에서 posts를 빼고 result를 넣으면 됩니다.
그럼
이렇게 게시물에서 제목과 링크만을 가져올 수 있습니다.
이제 앞선 전체 게시물을 불러온 데이터인 posts에서 slice를 해서 5개의 데이터만으로 한정시키면 현재 단계에서의 목표를 이룹니다.
import { NextResponse } from "next/server";
import { parseStringPromise } from "xml2js";
export async function GET() {
try {
const res = await fetch("https://v2.velog.io/rss/hwangrock1220");
const xml = await res.text();
const data = await parseStringPromise(xml, { explicitArray: false });
const posts = data.rss.channel.item;
const slicedPosts=posts.slice(0,5);
const result=slicedPosts.map((post:any) => ({
title:post.title,
link:post.link,
}));
return NextResponse.json(result, { status: 200 });
} catch (err: any) {
return NextResponse.json({ error: err.message }, { status: 500 });
}
}
카드 디자인 구현은 CSS 영역이므로 정리에는 제외하고,
이 글에서는 데이터를 렌더링하는 것만 정리하겠습니다.
데이터 렌더링은 시작점과 일정 간격을 가지고 했습니다.
과정은 계속 맞춰보면서 진행해서 제일 최적의 디자인을 찾았습니다.
CSS 스타일링은 생략하겠습니다.
아래와 같은 코드로 바꿔주면 데이터를 간격을 가지고 렌더링할 수 있습니다.
const itemsSvg = slicedPosts
.map(
(post: any, i: number) => `
<a href="${post.link}" target="_blank">
<text x="50%" y="${30 + i * 15}%" text-anchor="middle" class="comment">
${post.title}
</text>
</a>
`
)
.join("");
이제 postman으로 테스트를 해보면,
마음에 든 카드가 나온 것을 볼 수 있습니다.
디자인에 대해서는 좀 더 고민을 해야할거 같습니다.
XML과 json의 차이에 대해 한번 생각해볼 수 있었습니다.
XML은 태그가 많아서 읽기도 불편하고 파싱도 불편하지만,
json은 필드와 값이 보기 편하기도 하고, map을 이용해서 파싱을 하기도 편하다는 장점이 있다는 것을 깨달았습니다.
또, CSR와 SSR의 차이 또한 정리해볼 수 있었습니다.
렌더링은 웬만하면 프론트엔드의 역할을 하는 클라이언트 쪽에서 해야한다고 생각했었는데, 서버 측에서도 렌더링을 할 수 있다는 것을 깨달았습니다.
포스트 카드 사용은 아래처럼 하실 수 있습니다.
많은 관심 부탁드립니다..ㅎ
https://notion-serverless-voca.vercel.app/api/velog?id=(velog_ID)