(참고. expressjs.com에 가면 목차가 아래와 같이 나뉜다)

  • express()
  • Application
  • Request / Response
  • Router

 

Router 란?

 

router = handler나 url을 좀 더 관리하기 쉽게 해주는 기능 (미니 앱을 만들어준다고 생각하면 됨)
작업중인 주체를 기반으로 URL을 그룹화해준다.
ex) 

/users/edit, /users/delete etc ...
/videos/edit, /videos/delete etc...

 

# Wetube Reloaded

/ -> Home
/join -> Join
/login -> Login
/search -> Search

// -> 이 세 개는 글로벌 라우터이다. 홈에서 바로 갈 수 있는 페이지를 담고 있다.

/users/edit -> Edit user
/users/delete -> Delete user

/videos/watch -> Watch Video
/videos/edit -> Edit Video
/videos/delete -> Delete Video
/videos/comments -> Comment on a video
/videos/comments/delete -> Delete A Comment of a Video

 

 

 

Router 생성하기

 

const globalRouter = express.Router();
const userRouter = express.Router();
const videoRouter = express.Router();

 

생성은 했으니 실행하려면 어떻게 해야 할까?

우선 각 url (ex. /users)을 가져온다. 그럼 이제 앱이 준비가 된다.

app.use("/", globalRouter);
app.use("/users", userRouter);
app.use("/videos", videoRouter);

 

각 라우터의 첫 페이지를 만들어보자.

각 라우터 뒤에 페이지에 해당하는 함수를 추가해준다. 이때 이용되지는 않은 상태라는 점 주의!

 

const globalRouter = express.Router();
const handleHome = (req, res) => res.send("Home");

const userRouter = express.Router();
const handleEditUser = (req, res) => res.send("Edit User");

const videoRouter = express.Router();
const handleWatchVideo = (req, res) => res.send("Watch Video");

 

그리고 이제 get을 써서 사용해준다

const globalRouter = express.Router();
const handleHome = (req, res) => res.send("Home");
globalRouter.get("/", handleHome);

const userRouter = express.Router();
const handleEditUser = (req, res) => res.send("Edit User");
userRouter.get("/edit", handleEditUser);

const videoRouter = express.Router();
const handleWatchVideo = (req, res) => res.send("Watch Video");
videoRouter.get("/watch", handleWatchVideo);

 

이쯤에서 정리하자면, 

 

라우터:

const globalRouter = express.Router(); 

 

컨트롤러:

const handleHome = (req, res) => res.send("Home");

 

 

코드 정리하기(Clean Code)

 

모든 코드를 작성하고 잘 작동하는지 확인한 후 코드를 깔끔하게 정리할 필요가 있다. 그러기 위해 중복되거나 비슷한 내용들은 따로 폴더를 만들어 관리한다.

 

node.js에서 모든 폴더 및 파일은 서로에게 영향을 주지 않고 독립적이다.
따라서 다른 파일의 코드를 사용하려면 해당 내용을 import 해야 한다.

 

ex) 라우터 파일을 따로 만들 때 해당 파일의 최상단에 아래 내용을 적어줘야함.

import express = "express";

 

하지만 이렇게 별도 js 파일로 옮기고 나면 정작 server.js에는  globalRouter가 정의되지 않는다는 문제가 발생한다.

이를 해결하기 위해 globalRouter를 server.js에 import한다.

import 를 하기 전에는 반드시 변수를 export (import하려는 파일의 export default을 설정)해줘야 한다.

(내 프로젝트에 있는 모든 파일은 분리된 모듈이기 때문이다.

그래서 무언가를 외부에 공유하기 위해서는 export를 먼저 해줘야 한다.)

 

server.js 파일

import express from "express";
import morgan from "morgan";
import globalRouter from "./routers/globalRouter";
import userRouter from "./routers/userRouter";
import videoRouter from "./routers/videoRouter";

const PORT = 4000;

const app = express();
const logger = morgan("dev");
app.use(logger);

app.use("/", globalRouter);
app.use("/users", userRouter);
app.use("/videos", videoRouter);

const handleListening = () =>
  console.log(`✅ Server listening on port http://localhost:${PORT} 🚀`);

app.listen(PORT, handleListening);

 

각 라우터 파일 (ex. globalRouter)

import express from "express";

const globalRouter = express.Router();

const handleHome = (req, res) => res.send("Home");

globalRouter.get("/", handleHome);

export default globalRouter;

 

+ 여기까지 하고 실행했을때 상당한 오류가 났다...

 

무언가 익스프레스를 import 하는 과정에서 문제가 있나..싶은데 

node_modules 폴더 내에 express도 잘 살아있고,

각 파일당 문제가 될만한 부분도 없었다. 

 

다른 분들과 머리를 맞대고 에러 해결 방법을 생각해보다가 시도했던 방법은

 

1. package.json 폴더에 type:module 추가해보기

2. es6문법이 해석되지 않아서 그런건가? var express = require("express") 써보기

3. node_module 폴더 삭제하고 다시 설치하기

 

이 세 가지인데, 전부 하나도 통하지 않았다....

 

그러나 허무하게도 결론..은... 라우터 파일명이 .js로 되어 있지 않아서였다..!!

분명 .js로 네이밍을 하기는 했는데, 세 라우터 파일이 js 형식은 되었지만 파일명에 .js가 붙지 않은 상태로 저장된 것이다...

이걸 수정하자마자 기적처럼 에러가 해결되었다 휴

 

오늘의 교훈! 지난 파일명도 다시보자!

 

 

내보내기 (export)

 

router와 controller를 같이 쓰는 건 좋지않다. 앞으로 controller가 더 길어질텐데, 둘이 섞이면 구분이 어렵기 때문.

그러니 따로 작성한뒤 export 해줄 것!

 

controller 폴더를 만들어준 후 videoController.js 와 userController.js 파일을 생성한다.

이때 globalController.js가 없는 이유는 필요가 없기 때문이다.

-> join 같은 부분을 보더라도 user가 하는 것이기 때문에, 유저컨트롤러에 작성한다.

-> 홈에 들어가면 video가 보이기 때문에 비디오컨트롤러에 적어준다.

(글로벌라우터는 url을 깔끔하게 하기 위해 쓰는 것일 뿐! 그 외의 이유는 없다는 점 참고하자)

 

우선 아래와 같이 각 파일마다 컨트롤러를 작성해준다.

//userController.js
const join = (req, res) => res.send("Join"); 

//videoController.js
const trending = (req, res) => res.send("Home Page Videos");

이때 이렇게 작성한 컨트롤러를 어떻게 라우터로 가져올까?

 

1. 글로벌 라우터에서 했던 것처럼 export default join 하는 방법

 

globalRouter.js를 이렇게 수정해주고

import express from "express";
import join from "../controllers/userController";
import trending from "../controllers/videoController";

const globalRouter = express.Router();

globalRouter.get("/", trending);
globalRouter.get("/join", join);

export default globalRouter;

 

각 Controller 파일도 아래와 같이 바꿔준다.

const trending = (req, res) => res.send("Home Page Videos");

const watch = (req, res) => res.send("Watch");
const edit = (req, res) => res.send("Edit");

export default trending;

 

2. export를 앞에 붙여주는 방법

 

그러나 이때! watch와 edit은 어떻게 export할거냐? 라는 문제가 생긴다.

export default는 하나의 변수만 export할 수 있는데, 이미 trending을 export했기 때문이다.

 

여기서 export default와 각각의 변수를 export하는 것의 차이를 알 수 있다.

그냥 const 앞에 export를 붙여주기만 하면, 따로 export default 를 작성할 필요 없이 한 파일에 여러 개를 익스포트할 수 있다.

 

다만, export default 는 내보내는게 1개 밖에 없기에 node.js가 default로 설정된 걸 따라갈 수 있어서 변수명을 바꿔줘도 되지만.. export 는 내보내는게 여러가지라 꼭 선언된 변수명을 그대로 써줘야한다.

 

 

 

URL Parameters

 

/:id => url에 변수값을 넣어 줄 수 있게 해준다
id - 변수명
: - /:id id가 변수라고 인식하게 해줌

여기서 /upload를 위에 쓴 이유
respond 를 받아올때 /:id 의 변수 중 하나라고 인식하기 때문이다