코틀린 서버 연동 학습을 위해 단순한 Restful API 백앤드 서비스를 구름IDE에 준비해 보았습니다.
크레이가 가장 익숙한 언어는 PHP이지만 요즘 트랜드에 따라 Node.js 로 준비하였는데요.
관련 내용 공유드립니다.
무엇보다도 크레이 제 자신도 이 글을 다시 봤을 때 도움이 될거라는 확신을 가지고서 말이지요 :)
우선 이 글은 앞의 구름에듀에서 Node.js 를 설치하는 과정과
https://itadventure.tistory.com/577
구름IDE에서 Mysql 설치까지 선제 진행된 것을 가정합니다.
이 과정까지는 진행이 되어야 그 다음 단계 진행이 가능합니다.
https://itadventure.tistory.com/598
그럼 오늘도 렛츠 고우~
구름 IDE를 사용할 경우는 유의할 부분이 있는데요.
구름IDE에서 지원하는 소스편집 기능을 사용하기 위해서는 소스를 아래 폴더 또는 그 하위 폴더에 위치하여야 합니다.
/workspace/가상서버명/
크레이의 경우 가상서버명이 crayNodeServer 인데요.
소스코드를 /workspace/crayNodeServer/ 하위 폴더에 위치해야만 편집이 가능하다는 것이지요.
크레이는 /workspace/crayNodeServer 폴더 하위에 rest 라는 폴더를 생성하여 Restful API를 구성하였습니다.
이를 위해 폴더를 생성하고, npm 초기화 및 필요한 모듈을 설치하는 과정이 필요한데요.
아래 스크립트 내용이 바로 그것입니다.
# cd /workspace/crayNodeServer
# mkdir rest
# cd rest
# npm install pm2 -g
# npm -y init
# npm install fs express ejs request body-parser mysql2 moment
2개의 클래스 소스와 1개의 서버소스로 구성하였습니다.
모듈로 구성해도 되지만 크레이는 클래스를 더 선호하는 편이라서요 ㅎ..
/workspace/crayNodeServer/rest 폴더를 기준으로 3개의 소스 내용은 아래와 같습니다.
오류처리도 없고 보안도 없는 빈약한 소스코드이지만 Restful 서비스의 CRUD 요소는 모두 가지고 있지요.
( POST - 생성하고, GET - 읽고, PUT - 고치고, DELETE - 지운다! )
/server.js ( 서버 소스 )
const express = require('express');
const request = require('request');
const bodyParser = require('body-parser');
const querystring = require('querystring');
const { cray7db } = require('./include/db');
const memberObject = require('./include/memberclass');
console.log(memberObject);
const app = express();
var fs = require("fs");
global.cray7db = cray7db;
global.memberObject = memberObject;
// cRud
app.get('/list', function (req, res) {
(async () => {
try {
const data = await memberObject.list();
await res.setHeader('Content-Type', 'application/json');
await res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
await res.end(JSON.stringify(data[0], null, ' '));
}
catch (err) {
await res.json(err);
}
})();
})
// cRud
app.get('/:id', function (req, res) {
(async () => {
try {
await res.setHeader('Content-Type', 'application/json');
await res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
const data = await memberObject.get(req.params.id);
await res.end(JSON.stringify(data[0], null, ' '));
}
catch (err) {
await res.json(err);
}
})();
})
// Crud
app.post('/newuser', (req, res) => {
(async () => {
try {
const data = await memberObject.newuser(
req.query.member_id,
req.query.passwd,
req.query.nickname
);
await res.end(JSON.stringify({msg:'ok'}));
}
catch (err) {
await res.json(err);
}
})();
})
// crUd
app.put('/edituser', (req, res) => {
(async () => {
try {
const data = await memberObject.edituser(
req.query.member_id,
req.query.passwd,
req.query.nickname
);
await res.end(JSON.stringify({msg:'ok'}));
}
catch (err) {
await res.json(err);
}
})();
})
// cruD
app.delete('/deluser', (req, res) => {
(async () => {
try {
const data = await memberObject.deleteuser(
req.query.member_id
);
await res.end(JSON.stringify({msg:'ok'}));
}
catch (err) {
await res.json(err);
}
})();
})
var server = app.listen(8081, function () {})
/include/db.js ( mysql 에 접속하는 DB 연결 래핑 소스 )
const mysql = require('mysql2/promise'); // mysql 프로미스 모듈
const moment = require('moment'); // 현재시간
const charset = 'utf8'; // DB 문자 세트
const dbuser = 'cray7'; // DB 아이디
const dbpass = '여러분의DB패스워드를 적어주세요'; // DB 패스워드
// MYSQL 래핑 클래스
class mysqllap {
constructor(opts) {
if(opts==undefined)return;
try {
this.pool = mysql.createPool(opts);
}
catch(err){
console.log('error mysqllap::constructor');
console.log(err);
}
}
async query(sql, args) {
try {
var sqlparse = await this.pool.format(sql, args);
console.log(sqlparse)
var data = await this.pool.query(sqlparse);
console.log(data)
return await data;
}
catch(err){
console.log('error mysqllap::query');
console.log(err);
return await false;
}
}
}
const cray7db = new mysqllap({
user: dbuser, password: dbpass, charset: charset,
supportBigNumbers : true, bigNumberStrings : true,
host: '127.0.0.1', database: 'cray7db'
});
module.exports = { cray7db };
/include/memberclass.js ( 회원관리 클래스 소스 )
// MYSQL 래핑 클래스
class memberClass {
constructor(opts) {
}
// 회원정보 GET
async get(member_id) {
return await cray7db.query(
"SELECT " +
"idx, nickname, join_date, lastlogin_date, visit, point " +
"FROM member WHERE member_id = ? LIMIT 1",
[member_id]
);
}
// 회원목록
async list() {
return await cray7db.query(
"SELECT " +
"idx, member_id, nickname, join_date, lastlogin_date, visit, point " +
"FROM member ORDER BY idx;"
);
}
// 신규회원
async newuser(member_id, passwd, nickname){
await cray7db.query(
"INSERT INTO member SET " +
"member_id = ?, " +
"passwd = password(?), " +
"nickname = ?, " +
"join_date = NOW(), " +
"lastlogin_date = NOW(), " +
"visit = 0, " +
"point = 0;",
[member_id, passwd, nickname]
);
}
// 회원 정보 수정
async edituser(member_id, passwd, nickname){
await cray7db.query(
"UPDATE member SET " +
"passwd = password(?), " +
"nickname = ? " +
"WHERE member_id = ?;",
[passwd, nickname, member_id]
);
}
// 회원 정보 삭제
async deleteuser(member_id){
await cray7db.query(
"DELETE FROM member " +
"WHERE member_id = ?;",
[member_id]
);
}
}
memberObject = new memberClass();
module.exports = memberObject;
이제 위 소스를 구름IDE에서 작동하시려면 터미널에서 아래 명령어를 실행하면 되는데요.
node server.js
위 소스에서 포트번호는 8081이고, 서버 소스가 작동중이니 이제 테스트할 수 있을것 같지만 아직입니다.
지난 게시글처럼 구름IDE는 역시 포트번호를 그대로 사용할 수는 없구요.
포트포워딩을 외부에 열어주어야 합니다.
구름IDE 컨테이너 설정화면에 들어가
지난번과 비슷하게 8081이라는 포트번호를 추가하니 이번에는 53648이라는 포트번호가 할당되었네요.
이 경우 앤드포인트URL로 http://15.165.242.11:53648 을 사용할 수 있게 되었습니다.
한가지 더 준비되어야 할 부분이 있는데요.
바로 회원 테이블과 샘플데이터입니다.
MYSQL에 접속하여, 툴에서 입력하긴 했지만 쿼리문을 공유드리는게 간단해서,
테이블 생성문과 데이터 삽입 쿼리문을 공유드립니다.
CREATE TABLE `member` (
`idx` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '일련번호',
`member_id` varchar(20) CHARACTER SET utf8 DEFAULT '' COMMENT '회원아이디',
`passwd` varchar(50) CHARACTER SET utf8 DEFAULT '' COMMENT '패스워드',
`nickname` varchar(20) CHARACTER SET utf8 DEFAULT '' COMMENT '닉네임',
`join_date` datetime DEFAULT NULL COMMENT '가입일자',
`lastlogin_date` datetime DEFAULT NULL COMMENT '최종로그인',
`visit` int(11) DEFAULT '0' COMMENT '방문횟수(1일1회집계)',
`point` bigint(20) DEFAULT '0' COMMENT '포인트',
PRIMARY KEY (`idx`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
cray, cray2, cray3 3명의 사용자 정보를 삽입하는 SQL문입니다.
insert into `member` (`idx`, `member_id`, `passwd`, `nickname`, `join_date`, `lastlogin_date`, `visit`, `point`)
values('1','cray','','크레이','2022-12-26 23:08:32','2022-12-26 23:08:35','0','0');
insert into `member` (`idx`, `member_id`, `passwd`, `nickname`, `join_date`, `lastlogin_date`, `visit`, `point`)
values('2','cray2','','크레이2','2022-12-26 23:08:54','2022-12-26 23:08:57','0','0');
insert into `member` (`idx`, `member_id`, `passwd`, `nickname`, `join_date`, `lastlogin_date`, `visit`, `point`)
values('3','cray3','','크레이3','2022-12-26 23:09:11','2022-12-26 23:09:14','0','0');
이제 이렇게 데이터까지 입력했으니 REST API가 잘 작동하는지 확인해봐야겠지요.
우선 가장 기본적인 GET 동작은 웹브라우저에서 실행이 가능한데요.
웹브라우저에 아래와 같이 타이핑하니
http://13.209.255.71:53648/cray
아래와 같은 회원 1명의 JSON 데이터 결과물을 얻을 수 있었습니다.
[ { "idx": "1", "nickname": "크레이", "join_date": "2022-12-26T23:08:32.000Z", "lastlogin_date": "2022-12-26T23:08:35.000Z", "visit": 0, "point": "0" } ]
회원 목록도 동일한 GET 방식이기 때문에 아래와 같이 입력하면
http://13.209.255.71:53648/list
아래와 같은 JSON 데이터를 얻을 수 있는데요.
[ { "idx": "1", "member_id": "cray", "nickname": "크레이", "join_date": "2022-12-26T23:08:32.000Z", "lastlogin_date": "2022-12-26T23:08:35.000Z", "visit": 0, "point": "0" }, { "idx": "2", "member_id": "cray2", "nickname": "크레이2", "join_date": "2022-12-26T23:08:54.000Z", "lastlogin_date": "2022-12-26T23:08:57.000Z", "visit": 0, "point": "0" }, { "idx": "3", "member_id": "cray3", "nickname": "크레이3", "join_date": "2022-12-26T23:09:11.000Z", "lastlogin_date": "2022-12-26T23:09:14.000Z", "visit": 0, "point": "0" } ]
이렇게 생겨먹은 데이터를 가지고 코틀린에서 연동을 할 예정입니다.
관련 기술로 레트로핏인가가 가장 유명하더군요 ㅎㅎ
그 외에 회원정보를 추가하는 POST. 수정하는 PUT, 삭제하는 DELETE 등의 액션이 준비되어 있는데요.
이 3가지 액션은 웹브라우저에서 직접 테스트를 할 수가 없습니다.
그렇기 때문에 다른 방법으로 테스트를 해야 하는데요.
글이 길어지기 때문에 아쉽지만 그 방법은 다음에 공개드리도록 하겠습니다.
( 이제 잠자리로... 피곤하네요 ㅎㅎ )
그동안 블로그 방문횟수를 살펴보니 88만번이나 많은 분들이 블로그를 다녀가셨군요.
100만회 달성하면 이벤트라도 열어야 할것 같습니다 :)
오늘도 여전히 방문해주시는 모든 분들께 감사드립니다.
구독과 좋아요는 크레이의 탐구활동에 힘이 됩니다!
'코딩과 알고리즘' 카테고리의 다른 글
크레이의 앱개발 도전기 #12 - 레트로핏 연동1 ( 코틀린 ) (4) | 2023.01.02 |
---|---|
REST API와 포스트맨~! (0) | 2022.12.31 |
구름IDE에 MYSQL 설치/활용 (2) | 2022.12.26 |
크레이의 앱 개발 도전기 #11. 카페매장 주문기 (코틀린 연습) (4) | 2022.12.18 |
크레이의 앱 개발 도전기 #10. 세컨드라이프 정보 뷰어(코틀린) (2) | 2022.12.16 |