전날에는 tensorflow.js를 한번 훑어보고 다음 날 노드 공부를 시작하였다. 이전에 노드 공부하며 들었던 인프런 강의 중 괜찮았던 강의가 몇 개 생각나서 다시 들어볼 예정. 나 이렇게나 인프런 잘 이용하는데 인프런에서 상이라도 줘야되는거 아닌가 ~..
그나저나 공부해야할게 참으로 많 군 요 허허
📹 [Inflearn] 테스트주도개발(TDD)로 만드는 NodeJS API 서버 - 김정환 https://www.inflearn.com/course/%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%A3%BC%EB%8F%84%EA%B0%9C%EB%B0%9C-tdd-nodejs-api/dashboard
노드(NodeJS)
node.js는 확장성 있는 네트워크 애플리케이션(특히 서버 사이드) 개발에 사용되는 소프트웨어 플랫폼이다.
작성 언어로 자바스크립트를 활용하며 논블로킹(Non-blocking) I/O와 단일 스레드 이벤트 루프를 통한 높은 처리 성능을 가지고 있다.
내장 HTTP 서버 라이브러리를 포함하고 있어 웹 서버에서 아파치 등의 별도의 소프트웨어없이 동작이 가능하며 이를 통해 웹 서버의 동작에 더 많은 통제를 가능케 한다. (출처: 위키백과)
노드에서 모듈(module)이란? 노드로 개발한 어플리케이션을 이루는 기본 조직
기본 모듈
node.js에서 기본적으로 제공하는 모듈써드파티(third-party) 모듈
노드 모듈 패키지 관리 툴(NPM)로 설치한 모듈, node_modules 폴더 아래 설치됨- 사용자 정의 모듈
1 2 3 4 5
module.exports = { function1 : function1, function2 : function2, .... };
노드 특징
- 브라우저 밖에서 자바스크립트 코드 실행 가능
- 크롬 v8 엔진 사용
- 이벤트 기반의 비동기 I/O 프레임워크
- 싱글 스레드로 동작하는 이벤트 큐에 요청 저장
- 가벼운 이벤트의 경우 이벤트 루프에서 처리
- 무거운 이벤트(파일 읽고 쓰기, 네트워크 등 시간이 다소 걸리는 이벤트)의 경우 논블록킹 워커 스레드로 보내 처리
- 처리 후 다시 이벤트 큐에 전달
- CommonJS를 구현한 모듈 시스템 노드는 파일 형태로 모듈을 관리할 수 있는 CommonJS로 구현
1
const module = require('module');
ES6에서는 자바스크립트 자체 ES6 Module이라는 이름으로 모듈화를 지원하기 시작 > import
노드 vs 자바스크립트
javascript는 브라우저를 통해서만 작동하며 주로 클라이언트 개발을 위해 사용되어왔음 (브라우저 콘솔창을 통해 실행됨)
이랬던 javascript를 서버사이드로 옮겨와 브라우저 밖에서 사용할 수 있도록 한 것이 바로 node
노드를 통해 자바스크립트로 서버 개발이 가능해짐!
http 모듈 이용한 어플리케이션
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const http = require('http');
const hostname = '127.0.0.1'; // host
const port = 3000; // port
const server = http.createServer((req, res) => {
// routing
if(req.url == '/') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World!\n');
} else if (req.url == '/users') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('users\n');
}else {
res.statusCode = 404;
res.end('Not Found\n')
}
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
Express JS
node.js로 REST 서버를 편리하게 구현할 수 있도록 해주는 웹 프레임워크 중 하나 (그 외 Koa, Hapi 등이 있음)
1
npm install express
어플리케이션(application)
익스프레스 인스턴스로 서버에 필요한 기능을 추가하고 라우팅 설정, 서버를 요청 대기 상태로 만들 수 있다.
미들웨어(middle ware)
요청(req)과 응답(res) 객체, 요청-응답 중 다음 미들웨어 함수에 대한 액세스 권한을 갖는 함수로 구조 내에서 중간 처리를 위한 함수
next()로 다음 함수를 호출하지 않을 경우 에러 발생
- express 웹 어플리케이션 생성과 미들웨어 예제
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
const express = require('express'); const app = express(); function logger(req, res, next) { console.log('i am logger'); next(); // 다음 실행 } function logger2(req, res, next) { console.log('i am logger2'); next(); } app.use(logger2); app.use(logger); // i am logger2 -> i am logger app.listen(3000, function() { console.log('Server is Running!'); })
- 에러 미들웨어 예제
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
const express = require('express'); const app = express(); // 일반 미들웨어 function commonmw(req, res, next) { console.log('commonmw'); next(new Error('error occured')); } // 에러 미들웨어 function errormw(err, req, res, next) { console.log(err.message); next(); } app.use(commonmw); app.use(errormw); // error occured (commonmw error message) app.listen(3000, function() { console.log('Server is Running!'); })
에러가 발생할 때 앞에서 발생한 에러 객체를 인자로 받아서 사용
라우팅(routing)
요청 url에 대해 적절한 핸들러 함수로 연결해주는 기능 (Router 객체를 이용하여 라우팅도 가능)
1
2
3
4
5
6
7
8
9
10
11
app.use('/', function(req, res) {
// '/' 주소로 들어오는 모든 HTTP 메소드 요청 처리
});
app.get('/', function(req, res) {
// '/' 주소로 들어오는 GET 메소드 요청 처리
});
app.post('/data', function(req, res) {
// '/data' 주소로 들어오는 POST 메소드 요청 처리
});
테스트 주도 개발(Test Driven Dev.)
모카(Mocha)
nodejs 테스트 러너를 지원하는 테스트 프레임워크
📄 https://mochajs.org/Should
검증(assertion) 라이브러리로 assert 모듈을 불러오지 않고도 여러가지 검증 메서드 사용 가능, 가독성을 높혀줌
📄 https://github.com/tj/should.js/SuperTest
익스프레스 통합 테스트용 라이브러리, 내부적으로 익스프레스 서버를 가동시켜 실제로 요청을 보낸 뒤 결과 검증
📄 https://github.com/visionmedia/supertest
npm 모듈 설치
1
2
3
4
# 개발 의존성 모듈로 설치
npm install mocha --save-dev
npm install should --save-dev
npm install supertest --save-dev
package.json 의존성
1
2
3
4
5
6
7
8
"dependencies": {
...
},
"devDependencies": {
"mocha": "^9.1.2",
"should": "^13.2.3",
"supertest": "^6.1.6"
}
package.json 테스트 스크립트 추가 (mocha 테스트코드파일.js)
1
2
3
4
"scripts": {
"test": "mocha index.spec.js", // npm test
"start": "node index.js" // npm start
},
테스트할 js파일 마지막에 exports 추가
1
2
3
4
5
module.exports = {
function1 : function1,
function2 : function2,
...
};
테스트 파일 생성
~.spec.js 는 ~.js 에 대한 테스트 코드 파일
모카(mocha)
메서드- describe() : 테스트의 범위 설정
- it() : 단위테스트 설정
- done() : 비동기 단위 테스트 완료를 알려줌
- 검증(assertion)
- assert 모듈 이용
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* utils.js function capitialize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } */ const utils = require('./utils'); const assert = require('assert') describe('utils.js모듈의 capitalize 함수는', () => { it('문자열의 첫번째 문자를 대문자로 반환한다', () => { const result = utils.capitialize('hello'); assert.equal(result, 'Hello'); }) });
- should 모듈 이용 (가독성↑)
1 2 3 4 5 6 7 8 9
const utils = require('./utils'); require('should') describe('utils.js모듈의 capitalize 함수는', () => { it('문자열의 첫번째 문자를 대문자로 반환한다', () => { const result = utils.capitialize('hello'); result.should.be.equal('Hello') }) });
- assert 모듈 이용
- 검증 성공
- 검증 실패
예제) /users?limit=limit 만큼 사용자 목록 조회
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const express = require('express')
const app = express()
const morgan = require('morgan');
const port = 3000;
app.use(morgan('dev'));
// user list
var users = [
{id: 1, name: 'alice'},
{id: 2, name: 'bek'},
{id: 3, name: 'chris'},
]
app.get('/users', (req, res) => {
const limit = parseInt(req.query.limit, 10); // 정수로 타입 변경(10진수)
if (Number.isNaN(limit)) {
// limit이 정수가 아닐 경우 parseInt() 결과 NaN 반환
return res.status(400).end();
}
res.json(users.slice(0, limit)); //res.body
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
});
// test
module.exports = app;
index.spec.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
describe('GET /users는', () => {
describe('성공 시', () => {
it('1-1) 유저 객체를 담은 배열을 응답한다.', (done) => {
request(app)
.get('/users')
.end((err, res) => {
console.log(res.body);
res.body.should.be.instanceOf(Array);
done();
});
});
it('1-2) 최대 limit 갯수만큼 응답한다', (done) => {
request(app)
.get('/users?limit=2')
.end((err, res) => {
console.log(res.body);
res.body.should.have.lengthOf(2)
done();
});
});
});
// -- 성공시
describe('2) 실패 시', () => {
it('limit이 숫자형이 아니면 400을 응답한다.', (done) => {
request(app)
.get('/users?limit=two')
.expect(400)
.end(done);
})
})
})
해결
limit가 없을 때 기본값 10으로 설정1 2
// index.js에 추가 req.query.limit = req.query.limit || 10;
morgan 모듈 이용하여 주석 남기기
개발 의존성 모듈로 설치
1
npm install morgan --save-dev
스크립트 추가
1
2
3
const morgan = require('morgan');
app.use(morgan('dev'));
오랜만에 웹 플밍하니까 재밌는거 같기도하고.. 얼른 익혀서 캡스톤 해야쥐