본 스프린트는 Bitly 서비스 과정을 생각하면서 풀어본다
(url 축약 서비스)
스프린트 과정
1. POST /links은 url을 받아 단축 url로 만든다
Controller
- POST 요청이 들어온다
- 축약하려는 url이 기존 DB에 있는지 확인
- GET 요청을 통해 원본 URL 접속
<title>
태그의 내용을 가져온다- 새로운 레코드를 만든다 (원본 url, 타이틀)
- 새 레코드의 ID가 접속 방법이 된다
Model (상태를 나타내는 프로퍼티 / 동작을 나타내는 메서드)
- 기존 DB에 있는지 확인
- 새로운 레코드를 만든다
- 새 레코드의 ID
2. GET/links는 urls 테이블의 목록을 JSON의 형태로 반환한다
Controller
- GET 요청이 들어온다
- 라우터를 통해 links 컨트롤러로 분기
- 데이터베이스에서 urls 테이블 조회
- json으로 데이터 전송
Model
- 데이터베이스에서 urls 테이블 조회
3. GET/links/:id을 요청하면 url 필드값으로 리디렉션 한다
Controller
- GET 요청이 들어온다
- 라우터를 통해 links 컨트롤러 분기
- 데이터베이스에서 urls 테이블 조회
- url 파라미터
- Visits 필드의 값 1 증가
- Visits, 방문 횟수를 증가 시며주는 이유
(url 축약으로 사람 방문횟수를 기록하면 얼마나 비지니스 효과가 있는지 파악 할 수 있다)- 해당 url로 리디렉션
- 리디렉션 이란
(해당 url로 즉 축약한 url로 안내 하는 것)Model
- 데이터베이스에서 urls 테이블 조회
- Visits 필드의 값 1 증가
Sequelize 설정 후
시퀄라이즈에서 CRUD(Create, Read, Update, Delete) 작업은 sql문을 자바스크립트를 통해 만든다
쿼리는 프로미스를 반환하므로 then이나 async/await문법으로 다룰 수 있다
라우터
는 컨트롤러로 진입할 수 있게 도와주는 endpoint
다라우터에 컨트롤러를 연결해야 한다
예를 들어 /links URL로 GET 또는 POST 요청을 보낼 경우, links 컨트롤러의 메소드가 실행되도록 만들 수 있다
controller/links/index.js
module.exports = { get: async (req, res) => { }, post: async (req, res) => { } }
레코드를 조회하기 위해선, findOne, findAll 메서드를 사용한다
- 모든 데이터 findAll
- 하나의 데이터 findOne
routes/links.js에서 endpoint에 따라서 get, post요청 분기
const linksController = require('../controller/links')
controller를 require로 가져온 이유는 require가 객채를 반환 하기 때문에 사용.
const express = require('express'); const router = express.Router(); const linksController = require('../controller/links') router.get('/', linksController.get) router.get('/:id', linksController.get) router.post('/', linksController.post) module.exports = router;
router와 controller를 연결 하면 req를 받아 올 수있다
req.body
{ url: 'https://www.github.com' }
console.log에 req.body를 찍었을때 url이 깃헙 주소가 나오는 이유는 test에 명시 되어 있어서 그런거 같다
modules/utils.js
를 이용할 수 있다상기의 이미지와 같이 urls table의 url, title 필드에 값들을 저장 해야 한다
url 가져오기
POST method는 데이터를 서버로 전송한다
즉, request body에 url이 담겨져 있다
title 가져오기 및 url 비교
modules/utils.js
const request = require('request'); const rValidUrl = /^(?!mailto:)(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?@)?(?:(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))|localhost)(?::\d{2,5})?(?:\/[^\s]*)?$/i; exports.getUrlTitle = (url, cb) => { request(url, function (err, res, html) { if (err) { console.log('Error reading url heading: ', err); return cb(err); } else { const tag = /<title>(.*)<\/title>/; const match = html.match(tag); console.log(match.length) const title = match ? match[1] : url; return cb(err, title); } }); }; exports.isValidUrl = url => { return url.match(rValidUrl); };
modules/utils.js 파일 안을 보면 title태그를 가져오는 것을 볼수 있다
MYSQL
요청 바디 url이 table에 url이 있는지 없는 지 확인
url이 없다면 title 등록const queryString = `SELECT urls.title FROM urls where urls.urls = ${req.body.url}` if (queryString) { const queryString = INSERT INTO urls (url, title) db.query(queryString, (err, result) => { callback(err, result) }) }
쿼리문이 맞는지 모르겠다 (연습 필요)
ORM
## 4.GET 요청
> **controllers/links/indes.js**
const { url: urlModel } = require('../../models')
url의 변수명을 urlModel로 변경
> **SELECT * FROM urls**
module.exports = {
get: async (req, res) => {
const result = await urlModel.findAll()
res.status(200).json(result)
}
}