2023. 5. 30. 16:19ㆍInternational Sign Lang 프로젝트/백엔드
이전 글을 읽어와 주시면 감사하겠습니다 :)
오늘은 API 를 바로 작성해 볼 것입니다!
하지만 언제나 제가 글에서 얘기하듯, 무턱대고 코드 짜는 건
장기적인 관점에서... 는 사실 단기적인 관점에서도 지'양'할 일이죠.
그리고 아직 Node+Express 에 갓입문한 병아리이기 때문에
API를 작성하기 이전에 라우터에 관련한 세팅이라던지
REST API 작성을 고려한 설계에 대한 고민이 필요합니다.
1. app.js 란? 세팅하기
먼저 Express의 기본 구조는 다음과 같습니다.
app.js
이 파일은 주로 애플리케이션의 중심, 실행 주체 역할을 합니다.
Express 앱 설정, 미들웨어 설정, 라우팅 설정 등 대부분의 주요 설정이 이 파일에서 이루어집니다.
bin
이 폴더는 일반적으로 애플리케이션을 시작하는 스크립트를 포함하고 있습니다.
예를 들어, www 파일은 애플리케이션의 서버를 시작하는 데 사용됩니다.
package.json
이 파일은 NPM(Node Package Manager)에서 사용하는 것으로,
프로젝트의 메타데이터와 프로젝트에서 사용하는 의존성(dependencies)을 정의합니다.
public
이 디렉토리는 정적 파일들(HTML, CSS, JavaScript, images 등)을 저장하는 곳입니다.
이 파일들은 직접적으로 클라이언트에 서빙됩니다.
routes
이 폴더는 라우팅 로직을 포함합니다. 여기에는 특정 URL 패턴에 응답하는 라우트 핸들러가 정의됩니다.
views
이 폴더는 템플릿 엔진을 사용하여 렌더링 될 뷰 파일들을 포함합니다.
예를 들어, EJS나 Pug와 같은 템플릿 엔진을 사용하여 HTML을 동적으로 생성할 수 있습니다.
이 폴더에는 HTML 레이아웃과 템플릿들이 저장됩니다.
과거 웹 애플리케이션의 방식이던 SSR의 방식을 채용한다면
위에 있는 모든 파일과 폴더들은 필수요소입니다.
하지만 이번 프로젝트에서 서버는 프론트엔드 쪽과 REST API를 통한
JSON 형식의 데이터만 주고받는 식의 통신만 할 예정입니다.
즉, 템플릿 엔진에 관련한 폴더인 public, views 가 필요가 없습니다.
그렇다면 다음처럼 남게 됩니다.
app.js
bin
package.json
routes
그렇다면 우리의 설정이 끝났을 까요?
아니죠, 서버의 설정을 담당하는 app.js 에서의 설정을 고쳐야 합니다!
원래 app.js의 코드는 다음과 같습니다
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) { next(createError(404));});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page res.status(err.status || 500);
res.render('error');});
module.exports = app;
길다 그죠...?
여기서 템플릿 엔진에 관한 설정을 지우면 다음처럼 됩니다!
var express = require("express")
var path = require("path")
var cookieParser = require("cookie-parser")
var logger = require("morgan")
var indexRouter = require("./routes/index")
var usersRouter = require("./routes/users")
var app = express()
app.use(logger("dev"))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(cookieParser())
// routers
app.use("/", indexRouter)
app.use("/users", usersRouter)
템플릿 엔진에 관한 코드는 전부 없애도 무방합니다!
2. 이제야 첫 API 작성
과거에 작업했던 저의 법규 날리기 페이지입니다!
저렇게 법규를 날리면 프론트엔드 쪽에서는
사용자의 IP에서 from_country와 클릭한 나라(path태그)의 to_country를 body에 담아
POST 형식으로 백엔드에 날리게 하도록 설계했습니다!
// app.js
var countriesRouter = require("./routes/countries")
app.use("/countries", countriesRouter)
// countries.js
const express = require("express")
const router = express.Router()
router.post("/", function (req, res) {
const from_country = req.body.from_country
const to_country = req.body.to_country
// 올바른 데이터를 받았는지 확인하는 로직
// DB 에 저장하는 작업
res.json({
message: "Data Received",
from_country: from_country,
to_country: to_country,
})
})
생각보다 간단합니다만 `/countries` API는 프론트에서
from_country와 to_country를 받아서 DB까지 넣는 것이 역할입니다!
그전에 먼저 들어온 데이터에 대한 유효성 체크를 해야겠죠!
데이터 유효성 검증
// 올바른 데이터를 받았는지 확인하는 로직
if (from_country.length !== 2 || to_country.length !== 2) {
return res.status(400).json({
error: "Invalid country code",
})
}
모든 국가코드는 2글자이기 때문에
들어온 값이 2글자가 아니라면 400번 에러를 response로 돌려주기로 설정했습니다!
이제는 DB 에다가 값 넣기!
이제 거의 다 왔습니다!!
제 DBMS는 mysql 이기 때문에 mysql 모듈을 다운받고
해당 모듈을 통해 DB에 대한 connection을 진행하겠습니다!
const mysql = require("mysql2")
const fs = require("fs")
const [host, user, password, database] = fs.readFileSync("database_config.txt", "utf8").split("\n")
const db = mysql.createConnection({
host,
user,
password,
database,
})
router.post("", function (req, res) {
const from_country = req.body.from_country
const to_country = req.body.to_country
if (from_country.length !== 2 || to_country.length !== 2) {
return res.status(400).json({
error: "Invalid country code",
})
}
const query = "INSERT INTO isl (from_country, to_country) VALUES (?, ?)"
db.query(query, [from_country, to_country], function (err, result) {
if (err) {
console.log(err)
return res.status(500).json({
error: "Database error",
})
}
res.json({
message: "Data Received",
from_country: from_country,
to_country: to_country,
})
})
})
mysql connection을 만들 때 사실
파라미터 안에다가 하드코딩으로 user와 password 값을 가져와도 되지만
그렇게 할 경우, github에 올렸을 때 저의 아이디와 패스워드는 공공재 급으로 변하겠죠...?
그래서 이런 보안이 중요한 경우 외부 파일로 저장하고, 이를. gitignore 에다가 저 정합니다!
특이한 게 있다면, 제가 mysql 모듈을 가져와야 한다고 해놓고선
mysql2 모듈을 가져왔습니다!
원래는 mysql 모듈로 코드를 작성했었는 데
전혀 예상하지 못한 에러를 만나게 되어 mysql2 모듈로 수정을 하게 되었습니다!
이에 대한 글은 다음에서 확인해주세요!
TIL
새로운 프레임워크를 사용하다 보니 단순한 API를 작성하는 것도 오래 걸리더라고요... 배움의 길은 멀다
그래도 설계를 다 하면서 하니 계속 진도를 나아가는 데 있어서 나의 판단에 대한 의구심이 없어지는 것을
느낄 수 있었기에 예전보다 성장했다는 것을 배울 수 있었습니다!
GITHUB
https://github.com/xpmxf4/ISL_BackEnd
보셨다면 스타 하나 부탁드리겠슴돠!!!!
그리고 언제나 피드백은 환영입니다 :)
'International Sign Lang 프로젝트 > 백엔드' 카테고리의 다른 글
Day 12-2 : 솔직히 본인 테이블에 더미 데이터 1,000 개 넣어본 사람? 없으면 보자, 프로시저로 더미 데이터 생성하기 (0) | 2023.06.08 |
---|---|
Day 12-1 CSRF 와 CORS 는 매우 연관이 깊다?! (0) | 2023.06.08 |
Day 11 : 싸우자 해커야! CSRF, HttpOnly, CSP 대응하기 (0) | 2023.06.02 |
Day 8 : 가상 DOM 생성, 웹 스크래핑, 및 JSON 데이터 MySQL 저장 (후 많다 많아) (0) | 2023.05.29 |
Day 7 : 왜 굳이 웹 서버 프레임워크를 사용해야 하나? (0) | 2023.05.25 |