-
#2. API 서버 만들기카테고리 없음 2020. 1. 1. 15:47
200101 2pm
시작
api 서버 생성
기존에 만들었던 것을 API서버를 분리한다.
--> 마이크로서비스 아키텍쳐
당연 장단점이 있겠지 ?
nodebird 와 동일한 레벨로 nodebird-api 폴더 생성
nodebird :본 앱
nodebird-api : 토큰인증, json데이터
nodebird-call : 클라이언트
이런걸 하고싶다는 것!
nodebird-api 폴더생성
npm init
기존에 nodebird에서 사용했던 패키지는 거의 그대로 사용하기위해 설치한다.
npm i bcrypt connect-flash cookie-parser dotenv express express-session morgan mysql2 passport passport-kakao passport-local pug sequelize uuid
코드를 재사용한다.
기존 nodebird 폴더 내에서
- config
- models
- passport
- routes
- .env
복사
그리고 views 폴더도 만든다
설치한김에 nodemon 도 설치하자
npm i -D nodemon
app.js 도 생성
여기까지가 가장 기본적인 폴더 구조이다 ! ! !
"API를 만든다= 쉽게 얘기하면 누군가 우리꺼 이용해서 사용하게끔 해준다 "
=> 사용자에게 발급할 secret Key와 Domain Model을 만든다.
즉, models에서 domain.js 추가 생성
module.exports = (sequelize, DataTypes) => ( sequelize.define('domain', { host: { }, type: { }, clientSecret: { }, }, { timestamps: true, paranoid: true, }) );
이렇게 틀을 잡아놓는다.
- host는 사이트 열어줄 계정
- type은 무/유료 로 다르게 해줄려고
- clientSecret은 비밀번호 같은것.
제한사항을 다 적으면 이렇다
models/domain.js
module.exports = (sequelize, DataTypes) => ( sequelize.define('domain', { host: { type: DataTypes.STRING(80), allowNull: false, }, type: { type: DataTypes.STRING(10), allowNull: false, }, clientSecret: { type: DataTypes.STRING(40), allowNull: false, }, }, { validate: { unknownType() { console.log(this.type, this.type !== 'free', this.type !== 'premium'); if (this.type !== 'free' && this.type !== 'premium') { throw new Error('type 컬럼은 free나 premium이어야 합니다.'); } }, }, timestamps: true, paranoid: true, }) );
여기서 validate 는 sequelize에서 거르지못한 것? 자세한 내용들을 추가 확인하는 메서드이다.
추가했으니 models/index.js 에서도 추가를 해주자
db.User.hasMany(db.Domain); db.Domain.belongsTo(db.User);
기본적인 와꾸 짜는것만 알아도(이해해도)
엄청 큰것이구나.
- 페이지 만들고
-페이지에 대한 라우팅 연결하고
- 연결하면서 수행할 함수 설정하고
- 디비와 통신 열어주고
- 이를 각 index.js 에 연결해주고
- 최종적으로 app.js에 연결하면서
- 포트 설정까지 해주면
렌더링 되면서 기능을 수행할 수 있네
200101 5pm
clientSecret과 UUID
views/login.pug
routes/index.js
app.js
위 파일들을 다 업데이트 해줘야겠지 ?
routes/index.js
router.post('/domain', (req, res, next) => { Domain.create({ userId: req.user.id, host: req.body.host, type: req.body.type, clientSecret: uuidv4(), //비밀키 발급 }) .then(() => { res.redirect('/'); }) .catch((error) => { next(error); }); });
계속해서우리는 localhost:8002번을 만들고있는것이다. 이게 API로 쓰이는것이다
즉 여기서 비밀키를 발급해서 다른 사이트에서도 쓸수있는것이다.
이 부분을 조금 엄밀하게 말해봐야된다.
JWT와 jsonwebtoken패키지
npm i jsonwebtoken
그리고 jwt시크릿은 jwt 토큰발급 및 인증에 사용되므로 잘 ~ 보관해야된다 -> .env에 보관하자
.env
JWT_SECRET=jwtSecret
추가
토큰은 서버에서 서보로 요청할때.
JWT는 프론트나 서버 둘다 인증요도로 사용가능하다
clientSecret은 프론트 불가 .
이러한 상관관계와 근거가 궁금하네.
무튼!
실제 구현을 하기전에 이렇게 할 것이다.
routes/middleware.js 에 verify라는 것을 만든다.
http , req의 header에 authoriztation을 요청하면서 .env파일의 토큰과 일치하는지를 검사한다는게 핵심이다.
jwt 공식문서를 봐야되겟네
routes/middlware.js
exports.verifyToken = (req, res, next) => { try { req.decoded = jwt.verify(req.headers.authorization, process.env.JWT_SECRET); return next(); } catch (error) { if (error.name === 'TokenExpiredError') { // 유효기간 초과 return res.status(419).json({ code: 419, message: '토큰이 만료되었습니다', }); } return res.status(401).json({ code: 401, message: '유효하지 않은 토큰입니다', }); } };
그리고 v1 파일 생성
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.find({ 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); }); module.exports = router;
당연히 app.js에도 연결을 해줘야된다.
jwt신기하다
API 호출 서버 만들기
20200106 6am
클라이언트 역할을 하는 서버를 만들자
새로운 폴더 : nodebird-call
port는 8003번으로 할것
npm init npm i cookie-parser dotenv express express-session morgan pug axios
콜함수에서 중요한건 axios !
그리고 당연히 필요한 것들
- app.js
-views/error.pug
-routes/index.js
-app.js 도 기존 app.js 복사
(port 만 8003번으로 변경)
npm i -D nodemon
-error.pug
.env 파일이 중요하다
COOKIE_SECRET=nodebirdcall CLIENT_SECRET=0989a8af-067d-45df-b3f9-97c7ebd7e7fa
이때 CLIENT_SECRET은 API에서 던져주는 코드로 !
이젠, routes/index.js 를 해줘야겠지???
라우터는 기계적으로.
const express = requrie('express'); const router = express.Router(); router.get('/test', async(req,res,next)=>{ try { } catch (error) { console.error(error) return next(error) } }) module.exports = router;
이런느낌으로다가.
-매번 토큰을 받아올수없기떄문에 session에 토큰을 저장하는 형식이다.
-req에 토큰이 없으면, 토큰발급해주는데서 다시 요청
-토큰을 발급받으면 헤더에 넣는다.
토큰만료 에러가 났을때 경우도 생각
*참고1) api쪽 토큰 발급해주는 쪽 코드를 따라가보면서 실제 성공or실패 했을때 데이터가 어떻게 이동되는지를 꼭 따져봐야된다.
api / routes/ v1.js 쪽 인듯
*참고2) axios는 다른 서버에 요청을 보내는 간단하고 유용한 라이브러리
axios.매서드(주소,옵션)
--> 추후 백서 확인 필요
* 토큰 발급 과정, 매커니즘,
하....에러당황 localhost:8003/test 가 안들어가지네 ...
20.01.14 화
다음은...API작성 및 호출하기
이제남은건
- API작성 호출
- API 사용량 제한 해보기
-CORS 해결하기
- 무유료 구분
이것만 하면 #3 GIF 실시간 채팅방으로 넘어간다 (목표 : 경매까지 1/22 or 마스터 채팅방까지 ~1/22 )
계속 에러가 멈추지않는다.....중단
20.01.20.