기본설정 : https://github.com/amamov/teaching-nestjs-a-to-z/tree/main/01%20%EC%B2%AB%20%EC%8B%9C%EC%9E%91
Node, VSCode 설치 + Prettier 셋업 강의 :2분28초 vscode 추천 extension
REST 란 ?
REST 란 “Representational State Transfer” 의 약자이다. 월드 와이드 웹과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식이다.
REST란, “웹에 존재하는 모든 자원(이미지, 동영상, DB 자원)에 고유한 URI를 부여해 활용”하는 것으로, 자원을 정의하고 자원에 대한 주소를 지정하는 방법론을 의미한다고 한다.
이거 여러번 읽어보자..
https://docs.microsoft.com/ko-kr/azure/architecture/best-practices/api-design
강의자료로 letStart를 받았다. package.json파일을 보면, 여러 모듈이 있는데,아래 npm i 명령어를 실행하면, packjson에 있는 필요한 모듈들을 자동으로 설치해준다.
npm i
스크립트 명령어를 설정한 블록이다.
1. npm run start
해당 명령을 실행하면 자동으로 prestart에 해당하는 명령이 실행된다. "npm run build"의 명령어에 의해 tsc가 실행되고 js파일이 생성되면 마지막 start명령에 의해 해당 파일이 실행된다.
2. npm run dev:start
보다 시피 여기서 watch 가 실행되었다. 실시간으로 ts파일을 보다가 ts파일이 새롭게 저장되면 자동으로 빌드해준다.
tsc하면 해당 설정에 의해 tsc가 실행된다.
npm install express
해당 명령을 실행하면 아래와 같이 새로운 블록이 생성된다.
dependencies 에는 애플리케이션 동작과 연관된,
devDependencies 에는 애플리케이션 동작과 직접적인 연관은 없지만, 이름 그대로 개발할 때 필요한 라이브러리를 설치하시면 됩니다.
좀더 쉽게 설명하자면, 개발할때 라는말은 tsc로 js파일에 해당하게 빌드한다. 이는 개발하는 과정이고 실제 실행은 js로 한다. 고로 tsc에 해당하는건 devDependencies에 넣는다.
express 공식문서에 js파일로 사용하는 예제가 있다.
https://expressjs.com/en/starter/hello-world.html
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
타입스크립트 형태로 고치면
import * as express from "express"
const app : express.Express = express();
const port:number= 8000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
와 여기서 콜백함수가 쓰이는구나..
app.get에서 localhost:8000에 해당하는 요청을 처리해준다.
라우터: 엔드포인트와 해당 엔드포인트에서 실행돼야 할 로직을 연결해주는 역할
컨트롤러: 미들웨어의 일종이지만 메인 로직을 담당하므로 분리해서 관리
미들웨어: 메인 로직의 컨트롤러 앞뒤로 추가적인 일을 담당
https://expressjs.com/en/guide/writing-middleware.html
미들웨어란? 양쪽에서 데이터를 주고 받을수 있도록 매게역활을 하는것입니다.
그냥 개념을 이해하면 좋을거같습니다.
이런식으로 최종적으로 해당 URL에 응답하기 이전에 몇가지 단계를 거쳐 응답하게 할수있습니다.
사용법은 간단합니다.
아래 코드중 use가 있는데, use는 어떤 메소드든 상관없이 동작하게 됩니다. 일반적인 경우 해당 로직에 타면 응답이 완료되어 종료되겠지만 3번째 매게변수로 next가 있습니다.
이 next를 해당 메소드에서 마지막에 배치하면 use메소드가 끝나더라도 다음 메소드로 이동하게 됩니다. 이런식으로 요청의 마지막이 아닌 중간에 추가적으로 동작하게 하는 함수를 미들웨어라고 합니다.
import * as express from 'express';
import { Cat, CatType } from './app.model';
const app: express.Express = express();
app.use((req, res, next) => {
console.log(req.rawHeaders[1]);
console.log('this is logging middleware');
next();
});
app.get('/', (req: express.Request, res: express.Response) => {
res.send({ cats: Cat });
});
위의 코드와 비슷하지만 get에도 next라는 함수를 추가하여 get 요청에만 작동하는 미들웨어를 만들수도 있습니다.
app.use((req, res, next) => {
console.log(req.rawHeaders[1]);
console.log('this is logging middleware');
next();
});
app.get('/cats/som', (req, res, next) => {
console.log('this is som middleware');
next();
});
app.get('/', (req: express.Request, res: express.Response) => {
res.send({ cats: Cat });
});
이처럼 미들웨어는 로직에서 위치와 get, use, put등 여러 메소드를 이용하여 다양한 형태로 생성할수 있습니다.
정적으로 사용할 때 아래와 같이 사용하면 된다. 너무 간단해서 설명은 생략
app.get('/', (req: express.Request, res: express.Response) => {
res.send({ cats: Cat });
});
라우터 url설정한 곳을 보면 :id를 볼수 있다.
이는 임의의 :id값으로 들어온걸 활용하여 그에 맞게끔 반환해줄수있다.
:id로 들어온값은 req.params에 저장되는데, 이를 cat.id와 비교해서 일치하면 해당 cat을 반환해주었다.
응답으로 status를 지정해줄수도 있다.
app.get('/cats/:id', (req, res) => {
try {
const params = req.params;
console.log(params);
const cat = Cat.find((cat) => {
return cat.id === params.id;
});
res.status(200).send({
success: true,
data: { cat },
});
} catch (error) {
res.status(400).send({
success: false,
error: error.message,
});
}
});
주의
요청할때 이런식으로 json형태로 요청을 했는데, express에서는 json인경우 인식을못한다. 그래서 미들웨어를 통해 json을 받아올수 있도록 처리해주자.
바디가 json인경우 express에서 인식을 못하는데 이를 위해
아래 코드로 Expressjs에서 JSON Request Body 파싱해서 바디에 저장해두자.
express.json()은 미들웨어인데, next가 없지만, express에서 제공하는 미들웨어라 아마 내부적으로 next를 포함하고 있는거 같다.
post로 바꾸고. 핸들러를 생성하고
app.post('/cats', (req, res) => {
try {
const body = req.body;
console.log('모야? ', body);
Cat.push(body);
res.status(200).send({
success: true,
data: { Cat },
});
} catch (error) {
res.status(400).send({
success: false,
error: error.message,
});
}
});
아래 처럼 실행해주면 정상적으로 작동한다.
위에서 처럼 라우더나 미들웨어를 만들면 되지만 문제는 서비스가 많아 질 수록 코드가 너무 길어져서가독성이 떨어진다.
그래서 특정 라우터끼리 묶거나 파일을 옮겨서 관리하면 편하게 관리할수 있다.
이렇게 미들웨어를 위아래에 두고 중간에 라우터가 다른 라우터를 묶고있는 식으로 만들어보았다.
실습 : 예제중 Cat에 관한 라우터들은, 아래 처럼 cat.route파일에 모아서 관리하려고 한다.
app.js에 있던 기존 라우더에서는 app객체를 통해 express를 가지고 왓따. cats.route에서는 Router라는 이름을 가지고 왔고 라우터를 사용하기 위해 router 에 express를 넣어주었다.
그리고 기존 app.ts에서는 이런식으로 catsRouter를 호출해주었다. 한번 실행해보니, catsRouter내부의 라우터가 실행되더라도 app.ts는 밑에 있는 middleware까지 실행되고 종료된다.
cat데이터에 새로운 값으로 업데이터하거나, 부분적으로 업데이트, 데이터 삭제를 해보았다.
put을 한번 보자. put메소드로 받은 요청을 통해 CAT 내용을 업데이트해준다.
기존 아이디중에 일치하는 아이디를 body로 들어온 요청으로 바꿔주었다.
router.put('/cats/:id', (req, res) => {
try {
const params = req.params;
const body = req.body;
let result;
Cat.forEach((cat) => {
if (cat.id === params.id) {
cat = body;
result = cat;
}
});
res.status(200).send({
success: true,
data: {
cat: result,
},
});
} catch (error) {
res.status(400).send({
success: false,
error: error.message,
});
}
});
patch도 똑같은데, 딱 한군데만 수정해주면된다.
아래 부분만 수정해주면 patch 일때도 동작한다.
cat = body; //put 전체 업데이트
cat = { ...cat, ...body }; //patch 부분 업데이트
DELETE는 일치하는 아이디만 제거해 줬는데 filter 함수를 사용햇다. 일치하지 않는 아이디만 newCat에 다 저장한다 .
const newCat = Cat.filter((cat) => cat.id !== params.id);
res.status(200).send({
success: true,
data: newCat,
});