들어가며
한 6개월 전인가 만든건데 이제야 올리네요.
예전에 티스토리 블로그 글을 github readme 프로필에 올려두는 카드를 설정해놨었는데 언젠가 다시보니 엑박이 뜨더라구요
다시보니 ㅠ 티스토리 OpenAPI 서비스가 한참 전에 종료되었다고 하네요.
해당 레포에서는 티스토리 API를 사용해 정보를 가져오고 있어서 안된 것 같아요.
https://notice.tistory.com/2664
[안내] 티스토리 Open API가 종료됩니다.
안녕하세요. 티스토리팀입니다. 티스토리 기능을 외부에서 제어하고, 티스토리를 이용해 서비스 개발을 할 수 있도록 제공한 티스토리 Open API가 종료될 예정입니다. 이에 따라 Open API를 활용한
notice.tistory.com
모두들 다른 플랫폼으로 넘어 가시지만 티스토리 블로그를 아직 놓치 못하는 저로서 넘 슬프지만 그냥 하나 만들어봐야겠다 ~
라고 생각해 제가 사용할 용도로 하나 만들었답니다.
티스토리 카드
https://github.com/jokj624/tistory-post-card
GitHub - jokj624/tistory-post-card
Contribute to jokj624/tistory-post-card development by creating an account on GitHub.
github.com
위에는 github 레포 링크구요. 혹시나 사용하시려면 맘껏 쓰셔도 됩니다.
저 백엔드 개발자라. 너무 못생겨서 새로운 디자인과 색상을 추가하겠다 하심 하셔도 됩니다 plz!
갠적으로 다크모드 도대체 어떻게 조합해야할지 몰라서 대충 만들다보니 이상해졌어요.

Github README에 붙이면 요렇게 가장 최근에 작성한 게시글 정보로 블로그 소개 카드가 나오게 됩니다
개발 후기
일단 공개적으로 주는 API가 종료되었다고 하니 뭘로 가져오면 좋을까 하다 RSS를 생각하고 바로 적용했습니다.
RSS 란?
RSS(Really Simple Syndication 또는 Rich Site Summary)는 블로그, 뉴스 사이트 등 업데이트가 잦은 웹사이트의 최신 콘텐츠를 사용자가 웹사이트를 직접 방문하지 않고도 요약된 형태로 쉽게 받아볼 수 있도록 하는 기술 및 데이터 형식이라고 합니다.
이전에 회사분이 사이드 플젝했던 콘텐츠 아카이빙 앱 Havit을 보시고 RSS feed를 긁어와서 볼 수 있음 좋겠다는 피드백을 주신적이 있어서 갑자기 생각났어요 감사합니다 :)
티스토리에서 별도로 custom 하시지 않았다면 대부분 블로그링크/rss 로 들어가면 볼 수 있습니다.
아래처럼 블로그와 게시글 정보가 나오는데 요거를 긁어다 만들면 되겠다란 생각을 했습니다.

프로젝트 구조
Directory structure:
└── tistory-post-card/
├── README.md
├── package.json
├── vercel.json
├── .prettierrc.js
├── api/
│ ├── index.js
│ └── routes.js
├── templates/
│ └── card.js
└── utils/
├── rss.js
└── string.js
구조는 별거 없습니다.
전반적으로 이전에 쓰던 티스토리 뱃지, 카드 레포보고 어떤식으로 구현되었는지 참고했고 비슷하게 만들었어요.
배포는 Vercel로 진행했습니다. Vercel에 express 배포하려면 별도의 형식이 있어서 아래 공식 문서 참고했습니다.
https://vercel.com/docs/frameworks/backend/express
기본적은 흐름은 아래와 같습니다.
- API 요청
- 블로그 RSS 추출
- 추출한 변수들로 미리 만들어진 SVG 템플릿에 넣어 완성
- 완성된 svg API 응답
간단 설명
우선 어떤 형식의 카드를 만들지 디자인이 필요했는데요.
저는 개자이너니까 피그마에서 대충 선으로 뚜따뚜따해 카드 모양을 하나 만들었습니다.

이렇게 만든 다음 코드 내에 svg 형태로 템플릿을 만들어둬야 했습니다.
그래야 텍스트는 모두 변수로 바꿔 반환 할 수 있어서요.
이런 힘든 일은 제가 하지 않고 AI에게 시켰습니다.
피그마에서 SVG 파일 형식으로 저장한 후 AI에게 던져서 템플릿 형태로 만들어달라 요청 했어요.
exports.getPostCardSvg = (
postLink,
blogTitle,
description,
postTitle,
tags,
theme = 'light', // 'light', 'dark'
) => `
<svg
width="450"
height="120"
viewBox="0 0 450 120"
fill="${theme === 'light' ? 'white' : '#121212'}"
xmlns="http://www.w3.org/2000/svg">
<a href='${postLink}'>
${this.getStyles(theme)}
<rect x="0.5" y="0.5" width="449" height="119" rx="4.5" stroke="#EB531F" />
<g transform="translate(20,30)" >
${this.getTistoryLogoSvg()}
<text x="20" y="0" fill="black" class="blog"> ${blogTitle}
<tspan class="desc">${utilString.truncate(description, 40)}</tspan>
</text>
<text x="0" y="30" class="title"> ${postTitle} </text>
</g>
${this.getTagsSvg(tags, theme)}
</a>
</svg>
`;
이런 식으로 템플릿을 만들고 중간에 텍스트, 링크 등이 들어가야 하는 곳은 변수화해주었습니다.
theme에 따른 스타일도 좀 길어서 별도 함수로 분리했습니다.
RSS를 긁어오는 것도 만들어야했는데요.
이런것도 보통 라이브러리로 나와있습니다. 바로 npm에 검색해 인기 많은 라이브러리를 선택했습니다.
const Parser = require('rss-parser');
const parser = new Parser({
headers: { Accept: 'application/rss+xml, text/xml; q=0.1' },
});
exports.parseRss = async (url) => {
const content = await parser.parseURL(url);
const recentPost = content?.items[0];
const tags = recentPost?.categories;
return {
blogTitle: content?.title,
description: content?.description,
postTitle: recentPost?.title,
postLink: recentPost?.link,
tags: tags?.slice(1),
};
};
rss-parser 가 인기가 많아 보여 이거로 선택했습니다.
사용법은 위에 코드처럼 간단하게 Parser 인스턴스를 생성해준 후 url을 넣어 파싱해오면 됩니다.
저는 최신글 정보와 최신글의 카테고리 (태그로 쓸 예정) 를 뽑아왔습니다.
/**
* @apiRoutes /api/post?name=
*/
router.get('/post', async (req, res) => {
const { name, theme } = req.query;
if (!name) {
return res
.status(400)
.send({ code: 400, message: 'Blog name is required' });
}
if (theme && theme !== 'light' && theme !== 'dark') {
return res.status(400).send({ code: 400, message: 'Invalid theme' });
}
// 1. RSS 파싱
const { blogTitle, description, postTitle, postLink, tags } =
await utilRss.parseRss(`https://${name}.tistory.com/rss`);
if (!postTitle || !postLink) {
return res
.status(404)
.send({ code: 404, message: 'Not found recent post' });
}
// 2. SVG 템플릿에 파싱한 정보 전달
const cardSvg = template.getPostCardSvg(
postLink,
blogTitle,
description,
postTitle,
tags.length > 5 ? tags.slice(0, 5) : tags,
theme,
);
// 3. SVG 응답
res.setHeader('Content-Type', 'image/svg+xml');
res.send(cardSvg);
});
이렇게 뽑아온 정보를 svg 템플릿에 넣어 결과를 API 응답으로 전해주면 끝입니다.
svg 형태의 응답 값이기 때문에 Content-Type은 image/svg+xml 로 지정해줍니다.
이외에는 단순한 Express API 형태라서 큰 설명이 필요할 것 같진 않네요.
오랜만에 힘들지 않고 재밌는거 만들어서 즐거웠어요.
사용법
README에 티스토리 블로그 이름과 원하는 테마를 넣어 아래 링크 형식으로 삽입하면 됩니다.
https://tistory-post-card.vercel.app/api/post?name={your-blog-name}&theme={theme}
- `GET /api/post?name={tistory_blog_name}&theme={theme}`
Returns an SVG card for the latest post of the specified Tistory blog.
- `theme` (optional): `light`, `dark`. (default: `light`).
- `dark`: Dark background (white text).
- `light`: Light background (black text).

다른 카드들은 여러가지 뱃지나 색상을 지원하는 것 같은데 저는 제가 쓸 용도여서 그냥 이 정도만 만들었어요..
혹시 더 예쁘게 만들고 싶은 관심 있으시다면 언제나 PR 남겨주세요 :)
그럼 다들 행복한 연말 되세요!
'DEV > 잡다한 개발 일지' 카테고리의 다른 글
| MongoDB Associate Developer Node.js 자격증 합격 후기 (16) | 2024.10.13 |
|---|---|
| 사이드 프로젝트를 세상에 내놓는다는 것 - HAVIT (5) | 2023.07.29 |
| Oracle Cloud에 Jenkins를 구축해보자 (feat. nginx) (3) | 2023.07.08 |
| M1 MacOS Ventura ruby build failed error (Feat. XCode 14) (0) | 2023.01.18 |
| [SOPT] 29대 서버 파트장 돌아보기 - 1 (8) | 2022.09.03 |