Github을 이용한 무료 NextJS 주석 시스템 구축 [2/2부]

Github을 이용한 무료 NextJS 주석 시스템 구축 [2/2부]

반응형

이전 기사에서 우리는 주석 시스템을 위한 기본 인터페이스를 구축했다. 이제 우리는 의견을 저장하고 검색하기 위해 API 엔드포인트를 Github의 API와 통신하도록 프로그래밍해야 합니다.

설명 저장

먼저 댓글을 좀 저장해 봅시다. 페이지/api 경로에서 주석이라는 새 폴더를 만들고, 그 안에 저장 폴더와 마지막으로 파일 안에 [slug]ts를 만듭니다. 물론 원하는 대로 이름을 변경할 수 있습니다. 단일 경로(예: /api/comment)를 작성한 후 사용된 방법에 따라 다른 함수를 호출할 수도 있습니다.

설명을 저장하려면 다음을 수행해야 합니다.

주석에 상위 항목이 있는지 확인합니다.

부모가 있는 경우 이 설명을 부모에 추가해야 합니다.

그렇지 않으면 이 설명을 이미 가지고 있을 수 있는 설명 배열에 삽입할 수 있습니다.

두 경우 모두 먼저 이미 보유하고 있는 데이터를 요청하고 수정한 다음 다시 보고서를 업데이트해야 합니다.

데이터 준비

기본적인 NextJS API 함수부터 시작하겠습니다.

import type { NextApiRequest, NextApiResponse } from "next"; export default (req: NextApiRequest, res: NextApiResponse): Promise => { return new Promise(async (resolve) => { // Our code here }) }

이 기능에서는 먼저 API로 전송되는 데이터를 준비합니다.

// Import the modules we need import { encrypt } from "@lib/encryption/crypto"; import Comment from "@interfaces/Comment"; const newComment: Comment = { date: req.body.date, parentCommentId: req.body.parentCommentId, id: req.body.id, username: req.body.username, email: encrypt(req.body.email as string), content: req.body.content, children: req.body.children, }; const { slug } = req.query;

상위 및 하위 주석 병합

하위 주석을 부모 설명과 병합할 기능이 필요합니다. 기본 자바스크립트 개체로 작업하기 때문에

실제 부모를 찾기 위해 재귀를 사용합니다.

function appendToParent(comments: Array, newComment: Comment): Array { comments.forEach((comment) => { if (comment.id === newComment.parentCommentId) { comment.children.push(newComment); } else if (comment.children && comment.children.length > 0) { comment.children = appendToParent(comment.children, newComment); } }); return comments; }

데이터 업데이트

이제 새로운 의견 데이터가 있으니 이전 데이터를 가져와 수정해야 합니다.

Github의 API와 통신하기 위해 공식 라이브러리 @octokit/request를 사용했다. 지금부터 우리는 트라이 블록 안에서 작업하겠습니다.

import { request } from "@octokit/request"; try { // Here we request the document in JSON (vnd.github.v3+json) because // with raw we don't have the file sha const prevComments = await request( // we request a GET on this path "GET /repos/{owner}/{repo}/contents/{path}", { headers: { // github private token authorization: `token ${process.env.GITHUB_TOKEN}`, // how we want the file. In this case, we want a JSON accept: "application/vnd.github.v3+json", }, // Owner of the repo owner: "PandaSekh", // Name of the repo repo: "my-blog-repo", // the path. I save the comments in a folder named comments in the root path: `comments/${slug}.json`, // the branch ref: "prod", } ).catch((e) => { // We accept and will handle a 404 because not every post will have // comments. For any other error statusCode, throw an error. if (e.status !== 404) throw new Error(e); }); // [...] We'll add more code here }

이제 새로운 의견이 있고 이전 의견이 있는 경우 이를 병합하여 업데이트된 데이터를 저장할 수 있습니다. 우리가 이것을 어떻게 하느냐 하는 것은 이전의 논평의 존재 여부에 따라 다르다.

// Still in the try block // if prevComments is undefined, there are no previous comments. This is the first possibility. if (prevComments) { // get the data from the base64 encoded content and parse it as JSON. let data = JSON.parse( Buffer.from(prevComments.data.content, "base64").toString("ascii") ); // Save the sha. We need it to update the file later on const { sha } = prevComments.data; // Merge the new comment to the parent if it has one. Else, simply add it to the array. if (newComment.parentCommentId) { data = appendToParent(data, newComment); // Merge the parent and the child comment } else { data.push(newComment); } // Save the updated comments to Github const update = await request( "PUT /repos/{owner}/{repo}/contents/{path}", { headers: { // github private token authorization: `token ${process.env.GITHUB_TOKEN}`, // how we want the file. In this case, we want a JSON accept: "application/vnd.github.v3+json", }, // Owner of the repo owner: "PandaSekh", // Name of the repo repo: "my-blog-repo", // the path. I save the comments in a folder named comments in the root path: `comments/${slug}.json`, branch: "prod", message: `Updated comment on post ${slug}`, // Git commit message sha, // The sha we saved before content: Buffer.from(JSON.stringify(data), "ascii").toString("base64"), } ); res.status(200).json(JSON.stringify(update)); resolve(); ``` 그리고 이제 우리는 새로운 것에 대한 코멘트가 없을 경우를 대비해서 다른 코멘트를 씁니다. ```js else { const data = [newComment]; // Save the new comment to Github const update = await request( "PUT /repos/{owner}/{repo}/contents/{path}", { headers: { // github private token authorization: `token ${process.env.GITHUB_TOKEN}`, // how we want the file. In this case, we want a JSON accept: "application/vnd.github.v3+json", }, // Owner of the repo owner: "PandaSekh", // Name of the repo repo: "my-blog-repo", // the path. I save the comments in a folder named comments in the root path: `comments/${slug}.json`, branch: "prod", message: `New comment on post ${slug}`, // Git commit message content: Buffer.from(JSON.stringify(data), "ascii").toString("base64"), } ); res.status(200).json(JSON.stringify(update)); resolve(); } } catch (e) { res.status(500).json(e); resolve(); } ``` ### 전체 API 방식 참조용 전체 API 메서드 아래에 있습니다. ```js import { request } from "@octokit/request"; import type { NextApiRequest, NextApiResponse } from "next"; import Comment from "@interfaces/Comment"; import { encrypt } from "@lib/encryption/crypto"; function appendToParent( comments: Array, newComment: Comment ): Array { comments.forEach((comment) => { if (comment.id === newComment.parentCommentId) { comment.children.push(newComment); } else if (comment.children && comment.children.length > 0) { comment.children = appendToParent(comment.children, newComment); } }); return comments; } export default (req: NextApiRequest, res: NextApiResponse): Promise => { return new Promise(async (resolve) => { const newComment: Comment = { date: req.body.date, parentCommentId: req.body.parentCommentId, id: req.body.id, username: req.body.username, email: encrypt(req.body.email as string), content: req.body.content, children: req.body.children, }; const { slug } = req.query; try { const prevComments = await request( "GET /repos/{owner}/{repo}/contents/{path}", { headers: { authorization: `token ${process.env.GITHUB_TOKEN}`, accept: "application/vnd.github.v3+json", }, owner: "PandaSekh", repo: "my-blog-repo", path: `comments/${slug}.json`, ref: "prod", } ).catch((e) => { if (e.status !== 404) throw new Error(e); }); if (prevComments) { let data = JSON.parse(Buffer.from(prevComments.data.content, "base64").toString("ascii")); const { sha } = prevComments.data; if (newComment.parentCommentId) { data = appendToParent(data, newComment); } else { data.push(newComment); } const update = await request( "PUT /repos/{owner}/{repo}/contents/{path}", { headers: { authorization: `token ${process.env.GITHUB_TOKEN}`, accept: "application/vnd.github.v3+json", }, owner: "PandaSekh", repo: "my-blog-repo", path: `comments/${slug}.json`, branch: "prod", message: `Updated comment on post ${slug}`, sha, content: Buffer.from(JSON.stringify(data), "ascii").toString( "base64" ), } ); res.status(200).json(JSON.stringify(update)); resolve(); } else { const data = [newComment]; const update = await request( "PUT /repos/{owner}/{repo}/contents/{path}", { headers: { authorization: `token ${process.env.GITHUB_TOKEN}`, accept: "application/vnd.github.v3+json", }, owner: "PandaSekh", repo: "my-blog-repo", path: `comments/${slug}.json`, branch: "prod", message: `New comment on post ${slug}`, content: Buffer.from(JSON.stringify(data), "ascii").toString( "base64" ), } ); res.status(200).json(JSON.stringify(update)); resolve(); } } catch (e) { res.status(500).json(e); resolve(); } }); }; ``` ## 설명 받기 주석을 검색하는 방법은 웹 사이트를 구축하는 방법에 따라 다릅니다. 댓글이 거의 없을 것으로 예상했고 웹사이트가 완전히 정적이기를 바랐기 때문에 [slug] 안에 GetStaticProps 방식으로 댓글이 표시됩니다.tsx 페이지 모든 새 설명은 사이트 재배포 및 재구성을 트리거합니다. 적당한 양의 설명을 예상하는 경우 이 방법은 최선의 방법이 아닙니다. 이 경우 GetServerSideProps를 사용하는 것이 더 나을 수 있습니다. ```js // This method will vary depending on your needs export async function getStaticProps({ params }: { params: { slug: string }): Promise<{ props: Props }> { const comments = await getComments(params.slug); return { props: { comments, }, }; } async function getComments( slug: string ): Promise | null> { try { const comments = await request( "GET /repos/{owner}/{repo}/contents/{path}", { headers: { authorization: `token ${process.env.GITHUB_TOKEN}`, accept: "application/vnd.github.v3.raw", }, owner: "PandaSekh", repo: "your-blog-repo", path: `../../comments/${slug}.json`, ref: "prod", } ); return JSON.parse(comments.data as unknown as string); } catch (e) { return null; } } ``` 그게 다예요! 이것이 제가 제 무료 정적 댓글 시스템을 만든 방법입니다. 만약 당신이 의심이 든다면, 당신은 여기에 의견을 달거나 내 소셜 미디어에 나에게 편지를 쓸 수 있다.

from http://issue-disk.tistory.com/24 by ccl(A) rewrite - 2021-10-10 09:01:41