프로젝트 평가기준은 아래와 같다.
Node.js 실습문제 -환경 구축 1. 사용 할 OpenAPI - 개별적으로 사용함 2. node.js 구동 및 서버 실행(http. express 등을 이용함) 3. 클라이언트 html 을 구성함 4. DB 구성 및 웹서버를 연결함 *실습 순서 및 점수 1. node.js 서버 구동 및 웹과 DB 연결 2. API 호출 후 Response 출력(10점) 3. 공공데이터 API 를이용하여 얻은 데이터 적용(20점) 4. response 에서 <litems> 의 모든 요소를 파싱하여 DB에 저장하고 출력(10점) 5. 공공데이터 API 를이용하여 얻은 데이터 적용(20점) 5. DB E-R 다이어그램을 그리기(10점)
오늘은 클라이언트-서버 간 출력과정을 짚었고, 내일은 서버와 데이터베이스간 연결하는 것을 진행할 예정. 실질적으로 데이터에 들어가서 서버를 거쳐 클라이언트에 적용하고-클라이언트에서 데이터를 받아 데이터베이스에 집어넣는 것으로 Node.js의 과정이 끝난다.
내일은 데이터베이스 테이블 생성부터 연결까지 할 예정, 스키마 모델 생성이 어려울 수 있다고 하셨으니 예습을 해둬서 나쁠 건 없을 것 같다. 아직 프로젝트에 대한건 감이 잘 안 잡힌다. 미니 프로젝트: 제품판매 웹앱 구현 과 공공데이터 API 를 이용한 웹 페이지 출력, 두가지가 평가 기준에 들어가는건가...
포스트맨 다운로드
구현된 익스프레스 라우트를 테스트하기 위한 클라이언트 환경, 주로 클라이언트 환경이 없는 백앤드 개발자가 개발하고 있는 서버 프로그램이 정상구동 하는지 테스트를 할 수 있는 프로그램.
익스프레스 라우트 테스트를 하기 위해 node.js 폴더 생성 후 폴더를 불러왔다. 터미널을 열고 npm init 을 치면 node,js 에서 새로운 패키지를 만들기를 시작한다. 패키지와 패키지 락 등등이 생성된걸 모두 확인한 뒤 app.js 파일을 생성 - postman 에서 서버가 돌아가는지 시험해서 확인해보기 위해 아래와 같이 작성했다.
const express = require ( 'express' )
const app = express ()
const port = 3000
app . get ( '/' , ( req , res ) => { res . send ( 'Hello World!' )} )
app . post ( '/' , ( req , res ) => { res . send ( 'guro_1206' )} )
app . get ( '/customer' , ( req , res ) => { res . send ( 'get' )} )
app . post ( '/customer' , ( req , res ) => { res . send ( 'post' )} )
app . listen ( port ,() => { console . log ( `서버가 실행됩니다. http://localhost: ${ port } ` ) })
포스트맨에서 확인한 코드 결과는 더보기 참고
더보기
app.get('/', (req, res) => { res.send('Hello World!')} )
app.post('/', (req, res) => {res.send('guro_1206')} ) 결과
app.get('/customer', (req, res) => {res.send('get')} ) 결과
app.post('/customer', (req, res) => {res.send('post')} ) 결과
get이든 post든 해당되는 프로토콜 요청이 들어오면 그에 대해서 응답을 하는, 서버가 존재한다면 클라이언트와 주고 받는것만 확인하는 코드. 뭔가 들어오면 어떤 결과를 내 주는 것, 이게 서버의 동작이고 스프링부트에서도 웹 서버 동작이 동일하다.
서버가 DB와 주고받기 위해서는, 서버와 DB를 매치 시켜주는게 별도로 필요하다. (지금은 클라이언트-서버간 출력을 볼 것이다.)
app . get ( '/' , ( req , res ) => { res . send ( 'Hello World!' )} )
app . post ( '/' , ( req , res ) => { res . send ( 'guro_1206' )} )
app . get ( '/customer' , ( req , res ) => { res . send ( 'get' )} )
app . post ( '/customer' , ( req , res ) => { res . send ( 'post' )} )
위 코드는 서버가 어떻게 동작할지에 대해서 get 과 post로 받는 코드다. 위 코드는 없어도 웹 페이지 자체는 활성화 된다. (단지 출력 결과가 안 보일 뿐이다.)
const express = require ( 'express' )
const app = express ()
const port = 3000
app . listen ( port ,() => { console . log ( `서버가 실행됩니다. http://localhost: ${ port } ` ) })
하지만 이건 웹 서버를 활성화 하는 것이기 때문에, 위의 코드가 없으면 get 과 post가 있어도 웹서버가 활성화 되지 않는다. 참고하자.
7.2.3 라우트(Route)경로
const express = require ( 'express' )
const app = express ()
const port = 3000
//get방식으로 'host:port/acd' 혹은'host:port/abcd'를 호출했을 때
//'b?'는 문자'b' 가 0개 혹은 1개 있다는 것을 의미
app . get ( '/ab?cd' , function ( req , res ){ res . send ( 'ab?cd' ); });
//클라이언트에서 요청한 라우트 경로가 abcd, abbcd, abbbcd 등과 일치
//'b++'는 문자'b' 가 1개 이상 있다는 것을 의미
app . get ( '/ab+cd' , function ( req , res ){ res . send ( 'ab+cd' ); });
//클라이언트에서 요청한 라우트 경로가 abcd, abxcd, abanycd, ab123cd등과 일치
//'ab*cd'는 문자 'ab'와 문자 'cd'사이에 문자가 없거나 혹은 어떤 문자도 올 수 있다는 것을 의미
app . get ( '/ab*cd' , function ( req , res ){ res . send ( '/ab*cd' ); });
//클라이언트에서 요청한 라우트 경로가 abc 혹은 abcde 와 일치
//'(cd)?'는 문자 'cd'가 0번 혹은 1번 있을 수 있음을 의미
app . get ( '/ab(cd)?e' , function ( req , res ){ res . send ( '/ab(cd)?e' ); });
//클라이언트에서 요청한 라우트 경로에 'a'가 포함되어있는 경우
app . get ( /a/ , function ( req , res ){ res . send ( '/a/' ); });
//클라이언트에서 요청한 라우트 경로가 문자 'insert'로 시작하는 경우, 결과 확인안됨
// app.get(/^insert/, function(req,res){
// res.send('/^insert/');
// });
app . listen ( port ,() => {console . log ( `서버가 실행됩니다. http://localhost: ${ port } ` ) })
포스트맨에서 확인한 코드 결과는 더보기 참고
더보기
app . get ( '/ab?cd' , function ( req , res ){ res . send ( 'ab?cd' ); });
app . get ( '/ab+cd' , function ( req , res ){ res . send ( 'ab+cd' ); });
app . get ( '/ab*cd' , function ( req , res ){ res . send ( '/ab*cd' ); });
app . get ( '/ab(cd)?e' , function ( req , res ){ res . send ( '/ab(cd)?e' ); });
app . get ( /a/ , function ( req , res ){ res . send ( '/a/' ); });
마지막 코드( insert )는 결과가 확인이 되지 않아 보류했다.
실습. request로 파라미터를 추가해 호출하기
// request 구글 크롤링 하는 법 다시 해보기
const request = require ( 'request' );
//한글 안깨지는법
const iconv = require ( 'iconv-lite' );
request ({
method : 'GET' ,
qs : { q : '신사역 맛집' },
encoding : null ,
}, ( error , response , body ) => {
const decodedResult = iconv . decode ( body , 'euc-kr' )
console . log ( decodedResult );
});
교재처럼 출력이 되지는 않았는데, 이렇게 나오는게 맞다고 하셔서 이걸 더 고치지는 않았다. 왜 이렇게 나온건지는 잘 모르겠지만 넘어갔다.
7.2.4 라우트(Route)핸들러
const express = require ( 'express' )
const app = express ()
const port = 3000
const ex0 = function ( req , res , next ){
console . log ( '첫 번쨰 콜백 함수' );
next ();
}
const ex1 = function ( req , res , next ){
console . log ( '두 번쨰 콜백 함수' );
next ();
}
const ex2 = function ( req , res ){
console . log ( '세 번쨰 콜백 함수' );
}
app . get ( '/examples' ,[ ex0 , ex1 , ex2 ]);
app . listen ( port ,() => { console . log ( `서버가 실행됩니다. http://localhost: ${ port } ` ) })
서버가 실행 된 후, 서버에 접속하니까 콜백 함수가 출력되었다.
7.2.5 응답 메소드
종류가 다양하다는걸 살펴본 뒤 넘어갔다. 사용 방법만 알고 있으면 될 것 같다.
7.2.6 app.route()
get, post, put, delete 등의 라우트 메소드를 app.route() 로 받아서 각 라우트 메소드로 처리하는 방법. 처리방법마다 받는 방법을 맞추면 코드가 길어지고 불필요하게 중복되는 부분이 생기게 된다. app.route() 로 각 라우트 메소드를 처리하면 불필요하게 중복되는 부분을 줄이고 효율적으로 코드를 관리할 수 있음.
const express = require ( 'express' )
const app = express ()
const port = 3000
app . route ( '/customer' )
. get ( function ( req , res ){ res . send ( '고객 정보 조회' ); }) //HTTP 메소드 GET 요청에 대한 조회 처리
. post ( function ( req , res ){ res . send ( '신규 고객 추가' ); }) //HTTP 메소드 Post 요청에 대한 조회 처리
. put ( function ( req , res ){ res . send ( '고객 정보 수정' ); }) //HTTP 메소드 PUT 요청에 대한 조회 처리
. delete ( function ( req , res ){ res . send ( '고객 정보 삭제' ); }); //HTTP 메소드 Delete 요청에 대한 조회 처리
app . listen ( port ,() => { console . log ( `서버가 실행됩니다. http://localhost: ${ port } ` ) })
더보기
get ( function ( req , res ){ res . send ( '고객 정보 조회' ); })
post ( function ( req , res ){ res . send ( '신규 고객 추가' ); })
put ( function ( req , res ){ res . send ( '고객 정보 수정' ); })
delete ( function ( req , res ){ res . send ( '고객 정보 삭제' ); })
7.2.7 express.Router (중요)
express.Router클래스를 사용하면 라우트처리를 여러 개의 파일로 분리해서 기능에 맞게 구현할 수 있다. 나는 routes라는 이름의 폴더를 새로 생성하고, routes 폴더에 customer.js, product.js 파일을 만들어서 각각 라우트를 정의 했다.
정리하자면 아래와 같은 느낌으로 폴더를 만들고, 폴더 안에 라우트를 정의한 것이다.
routes 폴더
customer.js
router.get('/',function(req,res){ res.send('customer 라우트 루트'); });
router.post('/insert',function(req,res){ res.send('/customer/insert 라우트'); });
router.put('/update',function(req,res){ res.send('/customer/update 라우트'); });
router.delete('/delete',function(req,res){ res.send('/customer/delete 라우트'); });
prduct.js
router.get('/',function(req,res){ res.send('prduct 라우트 루트'); });
router.post('/insert',function(req,res){ res.send('/prduct/insert 라우트'); });
router.put('/update',function(req,res){ res.send('/prduct/update 라우트'); });
router.delete('/delete',function(req,res){ res.send('/prduct/delete 라우트'); });
const express = require ( 'express' );
const router = express . Router ();
//고객정보 조회를 위한 라우트
//app.js에서 기본경로에 /customer를 사용하기 때문에 /customer라우트 경로를 가짐
router . get ( '/' , function ( req , res ){
res . send ( 'customer 라우트 루트' );
});
//고객정보 추가를 위한 라우트
//app.js에서 기본경로에 /customer를 사용하기 때문에 /customer/insert라우트 경로를 가짐
router . post ( '/insert' , function ( req , res ){
res . send ( '/customer/insert 라우트' );
});
//고객정보 수정을 위한 라우트
//app.js에서 기본경로에 /customer를 사용하기 때문에 /customer/update라우트 경로를 가짐
router . put ( '/update' , function ( req , res ){
res . send ( '/customer/update 라우트' );
});
//고객정보 삭제를 위한 라우트
//app.js에서 기본경로에 /customer를 사용하기 때문에 /customer/delete라우트 경로를 가짐
router . delete ( '/delete' , function ( req , res ){
res . send ( '/customer/delete 라우트' );
});
module . exports = router ;
const express = require ( 'express' );
const router = express . Router ();
//고객정보 조회를 위한 라우트
//app.js에서 기본경로에 /prduct 사용하기 때문에 /prduct 라우트 경로를 가짐
router . get ( '/' , function ( req , res ){
res . send ( 'prduct 라우트 루트' );
});
//고객정보 추가를 위한 라우트
//app.js에서 기본경로에 /prduct 를 사용하기 때문에 /prduct/insert라우트 경로를 가짐
router . post ( '/insert' , function ( req , res ){
res . send ( '/prduct/insert 라우트' );
});
//고객정보 수정을 위한 라우트
//app.js에서 기본경로에 /prduct 를 사용하기 때문에 /prduct/update라우트 경로를 가짐
router . put ( '/update' , function ( req , res ){
res . send ( '/prduct/update 라우트' );
});
//고객정보 삭제를 위한 라우트
//app.js에서 기본경로에 /prduct 를 사용하기 때문에 /prduct/delete라우트 경로를 가짐
router . delete ( '/delete' , function ( req , res ){
res . send ( '/prduct/delete 라우트' );
});
module . exports = router ;
const express = require ( 'express' );
const customerRoute = require ( './routes/customer' ); //customer라우트 추가
const productRoute = require ( './routes/product' ); //product라우트 추가
const app = express ();
app . use ( express . json ({
limit : '50mb'
}));
app . listen ( 3000 , () => {
console . log ( 'Server started. port 3000' );
});
app . use ( '/customer' , customerRoute );
app . use ( '/product' , productRoute );
서버 테스트 결과는 접은 글 참고
7.3 에러 처리하기
웹 서버 구축 시, 에러 처리는 필수는 아니지만 넣어주는것이 좋다. 웹에서 어떻게 에러가 나는지 클라이언트에게 알려주면 그것을 보고 에러를 처리할 수 있기 때문에 효율적임.
const express = require('express')
const app = express()
const port = 3000
app.get('/error',function(req, res){
throw new Error('에러 발생')
//리우트에서 에러가 발생하면 익스프레스가 알아서 이를 잡아 처리함.
// 클라이언트로 500 에러코드와 에러 정보를 전달합니다.
})
app.listen(port,() => {console.log(`서버가 실행됩니다. http://localhost:${port}`) })
const express = require('express')
const app = express()
const port = 3000
app.use(function(err, req, res, next){
res.status(500).json({statusCode:res.statusCode, errMessage:err.message})
})
app.get('/error2',function(req, res, next){
next(new Error('에러발생'));
});
app.listen(port,() => {console.log(`서버가 실행됩니다. http://localhost:${port}`) })
실습. Express 모듈2 - response
const express = require('express');
const app = express();
app.get('/',(request, response) => {
const result = [];
const multipleNumber = 9;
for(let i = 1; i < 5; i++){
result.push({
number: `${multipleNumber}X${i}`,
multipe: multipleNumber * i,
});
}
response.send(result);
});
app.get('/error', (request, response) => {
response.status(404).send('404 ERROR');
});
app.listen(4000, () => {
console.log('Server is running port 4000!')
});
Server is running port 4000!
7.4 정적파일 제공하기
이미지, CSS, 자바스크립트 파일과 같은 정적 파일을 제공하려면 위에서 그랬듯, 폴더 안의경로나 파일을 지정해주면 URL 로 불러와서 웹브라우저를 통해 보여준다.
7.5 미들웨어 모듈
파비곤 제공, HTTP 요청로그를 남기거나 응답 시간을 기록하는 등, 요청과 응답 중간에 목적에 맞게 특정 기능을 하는 함수, 종류를 살펴보고 넘어갔다.
7.5.1 body-parser
body-parser 는 구문을해석해서 req.body 속성으로 사용하게 해 주는미들웨어로, 모듈을 쓰기 위해서는 터미널에서 npm install body-parser 인스톨로 명령어를 설치해야한다. (교재로 읽고 넘어감, 별도로 코드를 작성 하지 않았다. )
슬슬 프로젝트 주제를 잡아야 할 필요가 있다. 지금부터 대략 구상을 해야 늦지 않게 프로젝트를 시작, 마무리 할 수 있을 듯.