Node.js

node>API들 다른 파일로 분리하기 (Router)

연습노트 2024. 9. 19. 09:24

개발하다보면 app.get() app.post() 이런 코드가 몇백개 쌓일 텐데

이걸 한 파일에 계속 길게 적으면 나중에 뭔가 하나 찾고 수정하기 힘들 수도 있기 때문에

API들을 다른 파일로 쪼개놓는 것도 좋습니다.

 

 

app.get('/shop/shirts', (요청, 응답) => {
  응답.send('셔츠 파는 페이지입니다')
})

app.get('/shop/pants', (요청, 응답) => {
   응답.send('바지 파는 페이지입니다')
})  

연습용으로 API 두개를 위처럼 만들어놓고 시작합시다.

이제 이 API를 다른 파일로 빼고 싶을 때 어떻게 하는지 알아봅시다.

 

 

 

 

 

API 보관용 폴더랑 파일 만들기 

 

API들 보관할 폴더와 파일을 하나 만들어봅시다.

 

 

API가 웹페이지 보내는 역할을 하는 경우 라우트라고도 부르기 때문에 

routes 이런 식으로 작성하는 분들이 많고

파일 작명은 아무렇게나 합시다.

이제 shop.js 로 여러분이 빼고싶은 API들을 다 빼면 됩니다.

 

 

(shop.js)

const router = require('express').Router()

router.get('/shop/shirts', (요청, 응답) => {
   응답.send('셔츠 파는 페이지입니다')
})

router.get('/shop/pants', (요청, 응답) => {
   응답.send('바지 파는 페이지입니다')
})

module.exports = router 

1. 근데 셋팅용으로 router라는 변수를 만들어놓고

2. app.어쩌구들을 전부 router.어쩌구로 바꾸고

3. 마지막에 export 해야합니다.

이러면 분리 끝입니다.

 

router 변수가 뭐냐면 그냥 route들을 (API들을) 관리할 수 있게 도와주는 기능일 뿐입니다.

근데 이러면 끝이 아니라 

4. 원래 파일인 server.js는 저 router 변수를 import 해야 API들을 정상적으로 사용가능합니다.

귀찮지만 원래 자바스크립트 코드짤 때도 다른 파일로 코드를 뺄 때 export / import 혹은 module.export / require 문법을 씁니다.

 

 

어떻게 하냐면 라우터 파일 하단에

module.exports = router 라고 쓰면 이 파일에 있는 router라는 코드를 export할 수 있습니다.

그 다음에 다른 파일에서는 require('파일경로') 하면 export했던 변수를 가져다가 쓸 수 있습니다.

그래서 server.js에서 require() 가져다가 쓰면 됩니다.

 

 

(server.js)

app.use('/', require('./routes/shop.js') )

다른 파일에 있던 API를 쓰고 싶으면 이렇게 미들웨어식으로 장착해서 쓰게 되어있습니다.

이러면 이제 누가 /shop/shirts 로 접속하면 진짜 기능 잘 동작하나 확인합시다.

 

 

(참고) module.exports / require 대신 import / export 문법으로 바꿔서 쓸 수 있는데

그러려면 require쓴 부분을 전부다 import로 바꿔야해서 귀찮으니 그러고 싶으면 알아서 바꿔씁시다.

 

 

 

 

 

공통된 시작 URL은 단축가능

 

라우터로 분리한 파일들 보시면 

공통된 시작 URL이 있으면 이걸 좀 단축시킬 수도 있습니다.

지금 보면 분리한 API들은 /shop 이런 URL로 시작하지 않습니까?

그럼 하단처럼 바꿔도 똑같이 잘 동작합니다.

 

 

(shop.js)

const router = require('express').Router()

router.get('/shirts', (요청, 응답) => {
   응답.send('셔츠 파는 페이지입니다')
})

router.get('/pants', (요청, 응답) => {
   응답.send('바지 파는 페이지입니다')
})

module.exports = router 

 

(server.js)

app.use('/shop', require('./routes/shop.js') )

그래서 이렇게 쓰고 싶으면 쓰도록 합시다.

 

- app.use가 많을 때 "이건 /shop과 관련된 route들이군" 이런 식으로 구분이 좀 쉬워진다는 장점도 있음

- 그래서 API를 만들 때 관련있는 API들은 시작 URL을 비슷하게 만들어놔야 나중에 다른 파일로 분리하기 쉽습니다.

 

그래서 지금 글작성, 수정, 삭제 이런 기능들을 만들어놨는데

이것들도 URL들을 서로 비슷하게 만들어놓고 다른 파일로 빼는 식으로 심심하면 구현해봅시다.

 

 

 

 

 

 

라우터파일에서 DB쓰려면

 

안타깝게도 라우터 파일에는 db 변수 정의가 안되어있어서 db.collection 어쩌구를 할 수 없는데 

server.js -> shop.js 이렇게 db 변수를 export / require 하면 쓸 수 있을텐데

근데 이미 shop.js -> server.js 이런 방향으로 다른 변수를 보내고 있기 때문에 

그러면 파일2개가 서로 상호참조를 해버려서 좀 꼬이고 그럴 수 있습니다.

참고로 Node.js에선 상호참조 해도 별상관없긴함

 

깔끔한 해결방법은 그냥 db연결하는 코드를 아예 다른 파일로 빼버리고 

그걸 server.js에서도 require해서 쓰고 

그걸 router파일에서도 require해서 쓰고

그러면 될 수 있습니다.

 

 

(database.js)

const { MongoClient } = require('mongodb')
const url = 'DB연결URL~~'
let connectDB = new MongoClient(url).connect()

module.exports = connectDB 

1. database.js 파일을 아무데나 만들고 

2. server.js에 있던 new MongoClient(url).connect() 하는 부분을 옮겨줍니다.

3. 그걸 변수에 저장해서 exports 하고 필요한 파일에서 가져다쓰도록 합시다.

 

Q. db라는 변수를 exports하면 편할 것 같은데 왜 저딴 것만 exports함?

- db 변수에는 원래 늦게 데이터가 들어오는데 그런건 원래 exports 해서 쓰기 힘듭니다.

그리고 connectDB만 있으면 여기다가 기존에 하던것처럼 .then() 붙이면 안에 db변수 나옴

 

 

 

 

(server.js)

let connectDB = require('./database.js') //database.js 파일 경로

let db
connectDB.then((client)=>{
  console.log('DB연결성공')
  db = client.db('forum')
  app.listen(process.env.PORT, () => {
    console.log('http://localhost:8080 에서 서버 실행중')
  })
}).catch((err)=>{
  console.log(err)
}) 

그럼 server.js에선 아까 MongoClient().connect() 가 필요한 부분에서 이렇게 쓰면 끝입니다. 

그냥 MongoClient().connect() 를 다른 파일로 빼서 쓰고 있을 뿐입니다. 

 

 

 

 

(routes/shop.js)

let connectDB = require('./../database.js') //database.js 파일 경로

let db
connectDB.then((client)=>{
  console.log('DB연결성공')
  db = client.db('forum')
}).catch((err)=>{
  console.log(err)
}) 

shop.js 에서도 똑같이 사용할 수 있습니다. 

그럼 이 파일에서도 db라는 변수를 사용가능하니까 db.collection.어쩌구 맘대로 쓸 수 있습니다.

- 여기선 app.listen 그런거 써서 서버를 또 띄울 필요는 없을듯요

- 님들이 만든 database.js 파일 경로를 잘 적읍시다.

 

 

 

 

 

라우터 파일에만 middleware 등록하려면

 

라우터 파일에 있는 API들에만 미들웨어 적용하고 싶으면 

라우터 파일안에서 app.use() 대신 router.use()를 쓰면 됩니다.

그럼 그 파일에 있는 API들에만 미들웨어 적용해줍니다.

필요하면 쓰도록 합시다.

 

 

 

 

 

오늘의 숙제 : 

 

Q1. 하단과 같은 API를 server.js에 만들어놓고 다른 파일로 빼봅시다.

 

app.get('/board/sub/sports', checkLogin, (요청, 응답) => {
   응답.send('스포츠 게시판')
})
app.get('/board/sub/game', checkLogin, (요청, 응답) => {
   응답.send('게임 게시판')
}) 

checkLogin은 로그인여부 검사하는 미들웨어입니다.

로그인 후 /board/sub/sports 접속시 잘 보이면 성공입니다.

 

 

Q2. 글발행 수정 삭제하는 기능들도 심심하면 router로 분리해봅시다. 

 

둘 다 쉬워서 답은 없음