저번 글의 환경설정이 끝난 후 시일이 지났습니다. 예상과 다르게 업무 상황이 달라져서 결국 글을 이어가지 못하고 API 서버는 빠르게 구현하는 것으로 마무리 지었습니다.
다행히 추가 업무 중 하나로 API 서버의 기능을 추가하는 일이 들어왔습니다. 이번 기회에 추가 기능을 구현을 다뤄볼까 합니다.
그럼, 이어서 진행하겠습니다.
https://heinrain.tistory.com/6
[개발일지] nodejs로 API 서버 만들기 PART. 1
스마트팜 프로젝트가 있었습니다. 스마트팜 플랫폼이라고 하여 구현된 웹 애플리케이션입니다. 이 스마트팜 플랫폼과 관련하여 업무 하나가 저에게 떨어졌습니다. 왜 API 서버를 만들어야 하
heinrain.tistory.com
API 서버 환경 구성은 이전 글을 참고해 주시기 바랍니다.
현재 이미 만들어진 API 서버는 NodeJS로 1~2개의 데이터를 제공하는 기능을 가진 간단한 서버입니다. 추가된 요건은 기존 API 서버에 더미 데이터를 만들어 데이터를 제공해주는 기능을 추가해야 합니다.
전달받은 요건은 다음과 같습니다.
크게 나누면 3가지로 구분할 수 있습니다. 기존의 서버는 Spring MVC 패턴으로 특정 시간마다 자기 자신의 Controller를 호출하는 로직으로 구현되어 있었습니다.
기존 서버에 구현된 로직에서 배치 로직을 분리하여 API 서버로 구성해야 합니다.
분리해야 할 로직들은 현재 Spring Scheduler로 특정 시간마다 호출하고 있는 로직들입니다. 분리해야 할 로직들을 도식화하면 다음과 같습니다.
음.. REST API라 부르기엔 많이 부족합니다. 기존에 구현된 URL 주소도 딱히 REST API 형식을 따르지 않습니다.
이 부분에서 REST API 규약으로의 변경을 제안해 볼 수 있습니다. REST API로의 변경은 향후 타 인원이나 외부에서 데이터를 호출할 때 인터페이스 연동에 수월한 면이 있습니다. 실제로 REST API를 이용해 보면, 기존 방식보다는 URL만으로 데이터를 접근하기 편리하게 구성되어 있습니다.
하지만, 추가적인 외부 통신을 위해서라면 확장성을 고려해 REST API를 따르는 것이 유용하지만, 다음과 같은 제약이 있습니다.
이슈를 최소화하기 위해 기존의 데이터 형식, 리턴 방식, 응답 상태 코드까지 그대로 진행해야 합니다. 이러한 제약조건 안에서 요건을 해결해야 하기 때문에 기존의 규약을 따르면서 호출하는 주체만 변경하기로 했습니다. 표준을 따르는 것도 좋지만 환경에 따라 표준을 선택하는 것은 개발자와 팀의 몫입니다.
REST API에 대해 자세히 알고 싶은 분은 아래 포스트가 잘 정리되어 있습니다. 참고하시기 바랍니다.
https://meetup.toast.com/posts/92
REST API 제대로 알고 사용하기 : NHN Cloud Meetup
REST API 제대로 알고 사용하기
meetup.toast.com
기존에 구현된 주소를 그대로 따르기 위해 코드를 작성해 보겠습니다.
app.js로 이동합니다.
nodejs를 설치하고 프로젝트를 생성하면 자동으로 같이 설치되는 require.js로 해당 모듈을 불러온 뒤, app.use()로 주소를 지정할 수 있습니다.
actuator라는 API를 만들어야 하기 때문에 actuator.js를 생성해줬습니다.
// actuator.js
var express = require('express');
var router = express.Router();
// GET
router.get(주소,function)
// PUT
router.put(주소,function)
// POST
router.post(주소,function)
module.exports = router;
위와 같은 방법으로 API로 구현할 수 있습니다. app.js 에서 생성 actuator.js 모듈을 불러온 후, app.use로 url을 지정해주고 파라미터로 넘겨줍니다.
// app.js
var actuatorRouter = require('./routes/actuator'); // 모듈을 사용
app.use('/actuator',actuatorRouter);
URL기준으로 아래와 같은 구조로 진행하기로 했습니다. commonJS의 모듈을 활용한 기본 방식입니다.
처음 프로토타입 서버를 구성할 때에는 최대한 간단하게 구성하는 것이 좋습니다. 구현해야 할 기능이 많을 경우, 처음부터 모든 것을 고려하다가는 개발 속도가 늦어질 수 있습니다. 핵심 기능이나 공통 기능이 무엇인지 파악을 하고 살을 붙여가는 식으로 접근하면 시간을 단축할 수 있습니다.
위 설계 화면과 같이 API 서버에서 역으로 기존의 서버로 일정 시간마다 호출하는 기능이 필요합니다. NodeJS의 라이브러리들 중에 node-cron과 node-schedule로 배치 기능을 구현할 수 있습니다. 저는 node-cron을 사용하기로 했습니다.
const cron = require("node-cron");
module.exports.sensorAutoSendJob = () => {
cron.schedule("0 * * * * *", () =>{
// do something..
console.log("sensorAuto");
});
};
module.exports.groSensorAutoSendJob = () => {
cron.schedule("0 0 3 * * 7", () =>{
// do something..
console.log("groSensorAuto");
});
};
위와 같이 batch 함수를 만들어서 API를 호출할 예정입니다. batch.js 파일을 생성하여 module.exports로 app.js에서 호출합니다. 그리고 NodeJS에서 API를 호출하기 위해 'axios' 라이브러리를 사용하기로 했습니다.
// https://github.com/axios/axios
const axios = require('axios').default;
function sensorSetParam(){
return {
apiKey:"69b3e26e4dcac4816cf74416b6fdcc17bae7de9580674a76f5f5fda3f9fa7",
sensorType: "ENV",
prdlistCd : "80300"
};
}
module.exports.sensorAutoSendJob = () => {
cron.schedule("0 * * * * *", () =>{
// do something..
console.log("sensorAuto", new Date().toLocaleDateString('ko-kr'));
const data = sensorSetParam();
axios.put("https://localhost:8080/api/sensor.do",data);
});
};
이런 식으로 간단하게 구현합니다.
이전에는 html로 작성을 했었는데 generator를 활용하니 자동으로 pug 파일이 생성됩니다. 저도 pug를 활용하는 것은 이번이 처음이네요. 먼저 자동으로 생성된 layout.pug 파일을 작성합니다.
doctype html
html(lang='ko')
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
meta(charset='utf-8')
meta(http-equiv="X-UA-Compatible", content='IE=edge')
meta(name='viewport', content='width=device-width, initial-scale=1')
link(rel='stylesheet', href='https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css', integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N", crossorigin='anonymous')
script(src="https://code.jquery.com/jquery-3.6.1.min.js",integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=",crossorigin="anonymous")
script(src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js",integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN",crossorigin="anonymous")
script(src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.min.js", integrity="sha384-+sLIOodYLS7CIrQpBjl+C7nPvqq+FbNUBDunl/OZv93DB7Ln/533i8e/mZXLi/P+", crossorigin="anonymous")
link(rel="stylesheet", href="https://uicdn.toast.com/tui.pagination/latest/tui-pagination.css")
script(src="https://uicdn.toast.com/tui.pagination/latest/tui-pagination.js")
link(rel="stylesheet", href="https://uicdn.toast.com/grid/latest/tui-grid.css")
script(src="https://uicdn.toast.com/grid/latest/tui-grid.js")
body
block content
웹 UI를 위해 부트스트랩 프레임워크를 CDN으로 연결했습니다. 많이들 사용하는 Jquery도 연동했습니다. layout.pug 파일을 작성했으니 간단하게 index.pug 파일도 작성해줍니다.
extends layout
block content
h1= title
hr
p 본 페이지는 테스트를 위한 페이지입니다.
h3= '테스트'
div(class='m-3')
button(class='btn btn-outline-info', id='refresh_btn') 갱신하기
div(class='m-3')
div(id="actuator_grid")
div(id="pagination", class="tui-pagination")
script(src="/javascripts/index.js")
기존 JSP나 HTML과 비교했을 때에는 pug 구현이 훨씬 직관적이고 간단합니다. 서버에서 값을 내려받은 데이터를 JSP처럼 활용할 수 있습니다.
extends layout
block content
h1= message
h2= error.status
pre #{error.stack}
기본으로 생성되었던 error.pug 페이지입니다. 위 코드와 같이 백엔드에서 내려준 값을 화면에 바로 노출할 수 있습니다.
pug를 사용해보니 상당히 흥미롭습니다. 기존의 JSP의 장점을 가져온 것 같고, 문법도 직관적이라 구현이 간편하다는 느낌을 받았습니다.
pug에 관심 있으신 분들은 아래 사이트를 참고해 주십시오.
https://pugjs.org/api/getting-started.html
Getting Started – Pug
Getting Started Installation Pug is available via npm: $ npm install pug Overview The general rendering process of Pug is simple. pug.compile() will compile the Pug source code into a JavaScript function that takes a data object (called “locals”) as an
pugjs.org
이제는 기존에 구현된 소스코드를 살펴보고 NodeJS로 이관하는 작업을 진행하면 끝입니다. 여기서부터는 비즈니스 로직이 들어가기 때문에 다루지 않겠습니다.
처음엔 익숙하고 간단해 보였던 NodeJS로 빠르게 구현하려고 마음먹었는데, 요구하는 기능에 맞춰 구현하다보니, 기존에 활용해보지 않았던 라이브러리나 프레임워크도 활용하게 되네요. 프로토타이핑을 해봐야 사용해야 할 기술들이 명확해지는 것 같습니다.
새로운 언어와 신규 프레임워크를 활용해야 할 때에는 빠르게 프로토타입을 만들어 보는 것이 도움이 될 때가 있습니다. 저의 경험이 여러분에게 도움이 되셨길 바랍니다. 감사합니다.
[개발일지] 웹 애플리케이션 다국어 처리가 안되는 문제. Spring 자바에서 다국어 처리하기 (0) | 2022.11.24 |
---|---|
[개발일지] nodejs로 API 서버 만들기 PART. 1 (0) | 2022.10.14 |
[개발일지] 화면 기능 개발하기 (1) | 2022.10.05 |
[개발일지] 오류를 해결하기 위한 과정 PART 2. (2) | 2022.09.29 |
[개발일지] 오류를 해결하기 위한 과정 PART 1. (0) | 2022.09.28 |
댓글 영역