일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 호스팅영역
- 클래스
- javascript
- 웹소켓재시작
- Express
- gpt3.5turbo
- java
- 노드버전
- ChatGPT
- chatGPTAPI
- aiapi
- iam사용자
- Github
- 웹소켓연결
- 웹소켓연결끊김
- 자바
- class
- 버킷생성
- gitlab
- nodejs
- openaiapi
- git
- nvmrc
- Database
- aws
- db
- 패키지설치에러
- 클라우드
- gptapi
- GPT3.5
- Today
- Total
IT's Jenna
서버 API 만들기 본문
이제 본격적으로 DB의 데이터를 활용하는 서버 API를 만들어 보자.
우선 코딩 설명을 들어가기 전에 다시 한번 express 프레임워크의 구조를 정리해보았다.
- bin - www : 통신 관련 설정 (포트 및 http 관련)
- components : 모든 routes 에서 사용되는 공통 API들을 구분하여 정리
- config : 데이터 베이스 연결
- models : 각 routes에서 사용하는 데이터 베이스의 CRUD API 정의 (insert, update, delete, getList)
- public : 정적 파일 보관 장소
- routes : 라우팅 경로별 client에 응답 동작 설정 (POST, PUT, DELETE, GET)
- app.js : express 프레임워크의 메인 스크립트로서 라우팅 서버 추가 및 경로 설정
Tip! routes 와 models의 파일명 및 라이팅 경로는 모두 DB 테이블명과 일치시켜 주는 것이 코드 작성에 용이하다.
orders 테이블을 기준으로 스크립트를 보도록 하겠다.
우선 routes와 models 폴더에 orders.js 파일을 만들어 준다. 그리고 app.js에서 orders를 require로 불러오고 app.use로 라우팅 경로를 만들어준다. 그러면 이제 orders 라우팅 경로를 따라서 client가 해당 페이지에 접속할 수 있게 된다.
POST API를 예로 한번 보자.
//routes.orders
var express = require('express');
var router = express.Router();
const db = require('../components/db')
const model = require('../models/orders')
router.post('/', async function(req, res, next) {
const body = req.body
try {
console.log('body : ', body)
const connection = await db.beginTransaction()
const result = await model.insert(connection, body)
await db.commit(connection)
res.status(200).json({result})
} catch (err){
next(err)
}
})
localhost:3000/orders로 라우팅이 되었고, client로부터 post 요청을 아래와 같이 받는다.
{
"user_idx" : 3,
"goods_idx" : 6,
"qty" : 7,
"order_date" : "test date"
}
request의 body값을 받아 온다 : body : { user_idx: 3, goods_idx: 6, qty: 7, order_date: 'test date' }
db에 미리 설정해둔 beginTransaction()가 데이터베이스와의 연결을 시작하고 해당 connection을 return 한다. (관련 내용은 이전에 포스팅한 'Database 상태변화' 참고. 링크는 아래에.)
그리고 model.orders에 만들어둔 insert API를 통해 데이터베이스에 해당 값을 업로드한 쿼리문을 준비한다. 이때 insert API는 db와의 connection과 client로부터 받은 body값을 매개변수로 가져간다.
//models.orders
module.exports.insert = async (connection, options) => {
console.log("options : ", options)
// const {idx} = options
let query = 'INSERT INTO orders SET ? '
let values = options
return await db.query({
connection:connection,
query:query,
values:values
})
}
insert API에 미리 작성해둔 쿼리문에 options로 받아온 body 값들을 넣어준다.
//components.db
module.exports.query = async (options) => {
const connection = options.connection ? options.connection : await this.getConnection()
//조건 ? 참일경우 실행할 내용 : 거짓일 경우 실행할 내용
const query = options.query
const values = options.values
return new Promise((resolve, reject) => {
connection.query(
query,
values,
function (error, result, fields){
if (error) {
reject (error)
}
resolve(result)
}
)
})
}
db의 query API는 insert에서 받은 options를 바탕으로 데이터베이스와의 연결상에서 쿼리문을 준비한다.
이제 다시 routes/orders의 post로 돌아가서 commit으로 해당 connection의 동작을 수행시켜준다.
모든 과정이 문제없이 수행되면 status 200과 insert API의 return값이 다음과 같이 응답한다.
{
"result": {
"fieldCount": 0,
"affectedRows": 1,
"insertId": 6,
"serverStatus": 3,
"warningCount": 0,
"message": "",
"protocol41": true,
"changedRows": 0
}
}
client가 라우팅 경로로 접속하고 어떤 요청을 했을 때 서버가 어떻게 응답하는지의 전체 프로세스를 이해한다면 나머지 PUT과 DELETE도 크게 다르지 않다.
약간 다르게 응답하는 GET을 한번 더 보도록 하자. 목적은 user_id를 쿼리로 줬을 때 해당 유저의 모든 order를 받아오는 것이다.
//routes.orders
router.get('/', async function(req, res, next) {
const user_idx = req.query.user_idx
console.log("user idx :", user_idx)
const result = await model.getList({user_idx:user_idx})
res.status(200).json({result})
});
get API는 beginTransaction으로 connection을 받아오지 않는다. 당연히 getList의 매개변수에도 connection은 들어가지 않고 받아온 query만 들어간다.
//models.orders
module.exports.getList = async (options) => {
console.log("options : ", options)
const {user_idx} = options
let query = `SELECT * FROM orders
LEFT JOIN goods ON goods.goods_idx = orders.goods_idx ` //띄워쓰기 있어야 함!
let values
if (user_idx) { //WHERE 조건문 추가
query += 'WHERE user_idx = ?'
values = user_idx
}
return await db.query({
// connection:connection,
query:query,
values:values
})
}
options는 user_idx만 받아왔고 이렇게 받아온 user_idx가 있을 시에는 WHERE 조건문을 붙여서 해당 데이터만 표시할 수 있다.
그리고 이렇게 만든 query와 values값을 query API에 넘겨주는데 받아온 connection이 없기 때문에 당연히 connection은 넣어주지 않는다. 이때 의문을 가질 수 있다. 동작을 수행할 필요가 없어서 beginTransaction을 하지 않는다 해도 데이터 베이스의 값들을 받아오기 위해서 connection은 돼야 하는 거 아닌가?
해당 의문은 정확이 맞는 말이다! components/db의 query API를 보면 조건을 하나 달아놨다. connection이 있으면 해당 connection을 이용하고 connection이 없다면 getConnection으로 데이터베이스와 연결시켜준다.
POST, PUT, DELETE는 routes에서 데이터베이스와 연결되는 반면에 GET은 db의 query에서 데이터베이스와 연결된다고 볼 수 있다.
+ SELECT를 할 때 LEFT JOIN을 이용해서 제품에 대한 정보 역시 함께 불러올 수 있도록 했다. 이때 쿼리문을 연결시키기 위해서 쿼리문 뒤에 혹은 WHERE문 앞에 띄어쓰기를 해줘야 한다. 이거를 깜빡해서 쿼리문이 왜 안되는지 한참을 고민했었다...^^;;
goods 정보를 함께 불러오면 아래와 같이 볼 수 있다.
{
"result": [
{
"orders_idx": 6,
"user_idx": 3,
"goods_idx": 6,
"qty": 7,
"order_date": "test date",
"goods_name": "good4-2",
"goods_price": 789789,
"brand_idx": 1,
"category_idx": 1
}
]
}
DB에서 데이터를 불러오고 client에게 응답하고 또 client로부터 받은 요청을 DB에 업로드하는 전체 프로세스를 이해한다면 나머진 모두 반복적인 동작이다.
<참고>
jungeunpyun.tistory.com/23?category=911250
Database 상태변화
목표 : DB에 CRUD 동작을 하는 쿼리문을 만들어 보자 1. createPool 우선 express를 활용해서 goods라는 라우팅 환경을 하나 만들었다. 여기서 mysql과 통신해서 쿼리문을 동작시키고자 한다. 이때 서버와 my
jungeunpyun.tistory.com
'Backend > Backend 기본' 카테고리의 다른 글
TCP vs UDP (0) | 2021.04.29 |
---|---|
Swagger (0) | 2021.02.28 |
데이터베이스 모델링 (0) | 2021.02.18 |
formidable로 파일 업로드하기 (0) | 2021.02.18 |
Crypto (0) | 2021.02.01 |