SNS API 서버
nodebird-api로 돌아와 API 라우터를 완성해보자.
const express = require('express');
const jwt = require('jsonwebtoken');
const { verifyToken } = require('./middlewares');
const { Domain, User, Post, Hashtag } = require('../models');
const router = express.Router();
router.post('/token', async (req, res) => {
const { clientSecret } = req.body;
try {
const domain = await Domain.findOne({
where: { clientSecret },
include: {
model: User,
attribute: ['nick', 'id'],
},
});
if (!domain) {
return res.status(401).json({
code: 401,
message: '등록되지 않은 도메인입니다. 먼저 도메인을 등록하세요',
});
}
const token = jwt.sign({
id: domain.User.id,
nick: domain.User.nick,
}, process.env.JWT_SECRET, {
expiresIn: '1m', // 1분
issuer: 'nodebird',
});
return res.json({
code: 200,
message: '토큰이 발급되었습니다',
token,
});
} catch (error) {
console.error(error);
return res.status(500).json({
code: 500,
message: '서버 에러',
});
}
});
router.get('/test', verifyToken, (req, res) => {
res.json(req.decoded);
});
router.get('/posts/my', verifyToken, (req, res) => {
Post.findAll({where: {userID: req.decoded.id}})
.then((posts) => {
console.log(posts);
res.json({
code: 200,
payload: posts,
});
})
.catch((err) => {
console.error(err);
return res.status(500).json({
code: 500,
message: '서버 에러',
});
})
});
router.get('/posts/hashtag/:title', verifyToken, async (req, res) => {
try{
const hashtag = await Hashtag.findOne({ where: {title: req.params.title}});
if(!hashtag){
return res.status(404).json({
code: 404,
message: '검색 결과가 없습니다.',
});
}
const posts = await hashtag.getPosts();
return res.json({
code:200,
payload: posts,
});
}catch(err){
console.error(err);
return res.status(500).json({
code: 500,
message: '서버 에러',
});
}
});
module.exports = router;
node-api/routes/v1.js
GET /posts/my 라우터와 GET / posts/hashtag/:title 라우터를 추가했다.
내가 올린 포스트와 해시태그 검색 결과를 가져오는 라우터이다.
사용하는 측에서는 위의 API를 이용하는 코드를 추가한다. 토큰을 발급받는 부분이 반복되므로 이를 함수로 만들어 재사용하는 것이 좋다.
const express = require('express');
const axios = require('axios');
const router = express.Router();
const URL = 'http://localhost:8002/v1';
axios.defaults.headers.origin = 'http://localhost:4000'; // origin 헤더 추가
const request = async (req, api) => {
try{
if(!req.session.jwt) { //세션에 토큰이 없으면
const tokenResult = await axios.post(`${URL}/token`, {
clientSecret: process.env.CLIENT_SECRET,
});
req.session.jwt = tokenResult.data.token; //세션에 토큰 저장
}
return await axios.get(`${URL}${api}`,{
headers: { authorization: req.session.jwt},
}); //API 요청
}catch(err){
if(err.response.status === 419){ //토큰 만료시
delete req.session.jwt;
return request(req, api);
}//419 외의 다른 에러
return err.response;
}
};
router.get('/mypost', async(req, res, next) => {
try{
const result = await request(req, '/posts/my');
res.json(result.data);
}catch(err){
console.error(err);
next(err);
}
});
router.get('/search/:hashtag', async (req, res, next) => {
try{
const result = await request(
req, `/posts/hashtag/${encodeURIComponent(req.params.hashtag)}`,
);
res.json(result.data);
}catch(err){
if(err.code){
console.error(err);
next(err);
}
}
});
router.get('/test', async (req, res, next) => { //토큰 테스트 라우터
try{
if(!req.session.jwt){
const tokenResult = await axios.post('http://localhost:8002/v1/token', {
clientSecret: process.env.CLIENT_SECRET,
});
if(tokenResult.data && tokenResult.data.code === 200){ //토큰 발급 성공
req.session.jwt = tokenResult.data.token; // 토큰 저장
}else{//토큰 발급 실패
return res.json(tokenResult.data);
}
}
//토큰 테스트
const result = await axios.get('http://localhost:8002/v1/test', {
headers: {authorization: req.session.jwt},
});
return res.json(result.data);
}catch(err){
console.error(err);
if(err.response.status === 419){// 토큰 만료 시
return res.json(err.response.data);
}
return next(err);
}
});
module.exports = router;
nodecat/routes/index.js
request 함수는 NodeBird API에 요청을 보내는 함수이다. 자주 재사용되므로 함수로 분리했다.
먼저 요청의 헤더 origin 값을 localhost:4000으로 설정한다. 어디서 요청을 보내는지 파악하기 위해 사용하며, 나중에 주소가 바뀌면 이 값도 따라서 바꾸면 된다.
세션에 토큰이 없으면 clientSecret을 사용해 토큰을 발급받는 요청을 보내고, 발급받은 후에는 토큰을 이용해 API 요청을 보낸다. 토큰은 재사용을 위해 세션에 저장한다. 만약 토큰이 만료되면 419 에러가 발생하는데, 이때는 토큰을 지우고 request 함수를 재귀적으로 호출하여 다시 요청을 보낸다.
GET /mypost 라우터는 API를 사용해 자신이 작성한 포스트를 JSON 형식으로 가져오는 라우터이다.
현재는 JSON 으로만 응답하지만 템플릿 엔진을 사용해 화면을 렌더링 할 수 있다.
GET /serach/:hashtag 라우터는 API를 사용해 해시태그를 검색하는 라우터이다.
자신의 게시글 목록을 불러오는 것이므로 당연히 사람마다 결과가 다르다. 또한, NodeBird 앱에 올린 게시글을 가져오는 것이므로 게시글을 올리지 않았다면 아무 정보도 표시되지 않는다.