ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • #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신기하다

    https://jwt.io

     

    JWT.IO

    JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

    jwt.io

     

     

     

    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.

     

    댓글

실험중인 삶, Life is not a race