일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
29 | 30 | 31 |
- Babel standalone
- Three-fiber
- webrtc
- methodChannel
- Flutter
- Completer
- swagger-typescript-api
- userevent_tracker
- Three js
- androidId
- Prism.js
- react
- web track
- identifierForVender
- typescript
- Raycasting
- Game js
- Redux
- node
- uint16array
- Excel
- KakaoMap
- REST API
- FirebaseAnalytics
- uint8array
- babel
- RouteObserver
- code editor
- jszip
- Image Resize typescript
- Today
- Total
Never give up
React, Node - Rest API with sqlite3 (beginner) - 1 본문
이전에 만들었던것을 조금 더 개선시켜서 만들어봤습니다
(링크 : https://devmemory.tistory.com/77)
node는 sqlite3를 연결, 서버부분 에러처리 추가
react는 자잘한 에러 수정 및 pagination 추가
그리고 proxy추가 및 변경된 부분 양쪽 다 처리
크게 이 3가지입니다
이번 포스트에서는 node랑 proxy 셋팅하는 부분만 넣고
react부분은 다음 포스트에 적을 예정입니다
proxy setup
const {createProxyMiddleware} = require('http-proxy-middleware')
module.exports = function (app) {
app.use(
createProxyMiddleware('/api',{
target: 'http://localhost:8080/',
changeOrigin: true
})
)
}
http prox middleware를 사용해서 /api경로에 8080포트를 넣어줍니다
이 작업을 하게되면 3000포트 사용시 localhost:3000/api로 8080/api에 접근이 가능합니다
(8080도 사용 가능합니다)
db helper
const sqlite3 = require('sqlite3').verbose()
const db = new sqlite3.Database('./server/db/task.db')
const create = () => {
db.run('create table if not exists task(id integer, title text, day text, reminder integer, hide integer)', (err) => {
if (err) {
console.log(err.message)
return
}
console.log('db created')
// for(let i = 1 ; i < 45 ; i++){
// insert({ id: i, title: `Test - ${i}`, day: `test date - ${i}`, reminder: Math.random() < 0.4, hide: Math.random() < 0.2 })
// }
})
}
create()
const insert = async (task) => {
return new Promise((res, rej) => {
db.run(`insert into task(id,title,day,reminder,hide) values (?,?,?,?,?)`, [task.id, task.title, task.day, task.reminder ? 1 : 0, task.hide ? 1 : 0], (err) => {
if (err) {
console.log(err.message)
return rej(err)
}
console.log(`insert task(${JSON.stringify(task)})`)
return res(true)
})
})
}
const getLength = async () => {
return new Promise((res, rej) => {
return db.get('select count(*) from task where hide = 0', (err, row) => {
if (err) {
console.log(err.message)
return rej(err)
}
console.log(`length : ${row['count(*)']}`)
return res(row['count(*)'])
})
})
}
const getAllTasks = async () => {
return new Promise((res, rej) => {
return db.all('select * from task where hide = 0 order by id desc', (err, rows) => {
if (err) {
console.log(err.message)
return rej(err)
}
console.log(`get all result : ${rows?.length}`)
rows.forEach((e, i) => {
rows[i].reminder = e.reminder === 1
rows[i].hide = e.hide === 1
})
return res(rows)
})
})
}
const getSingleTask = async (id) => {
return new Promise((res, rej) => {
const sql = `select * from task where id = ${id} and hide = 0`
return db.get(sql, (err, row) => {
if (err) {
console.log(err.message)
return rej(err)
}
if (row) {
row.reminder = row?.reminder === 1
row.hide = row?.hide === 1
}
console.log(`get single result : ${JSON.stringify(row)}`)
return res(row)
})
})
}
const getRange = async (offset, limit) => {
return new Promise((res, rej) => {
const sql = `select * from task where hide = 0 order by id desc limit ${limit} offset ${offset}`
return db.all(sql, (err, rows) => {
if (err) {
console.log(err.message)
return rej(err)
}
rows.forEach((e, i) => {
rows[i].reminder = e.reminder === 1
rows[i].hide = e.hide === 1
})
console.log(`get range result : ${rows.length}`)
return res(rows)
})
})
}
const updateTask = async (key, value, index) => {
return new Promise((res, rej) => {
const sql = `update task set ${key} = ${value ? 1 : 0} where id = ${index}`
return db.run(sql, (err) => {
if (err) {
console.log(err.message)
return rej(err)
}
console.log(`update at ${index} => ${key} : ${value}`)
return res(true)
})
})
}
module.exports = {
create,
insert,
getAllTasks,
updateTask,
getRange,
getSingleTask,
getLength
}
간단한 부분은 넘어가고 필자가 고민했던 부분들만 간단히 말씀드려보자면
먼저 Promise를 굳이 사용한 이유는 sqlite3가 비동기가 아니어서
별도로 처리를 해줘야된다고 해서 이러면 되지 않을까? 해서 한번 해봤는데 다행이도 잘 작동을 하더군요
그리고 pagination구현을 하는데 js로 계산해서 넣다보니 가려지는값(hide = true)들 때문에
불러오는 갯수가 일정치 않아서 limit offset을 활용해봤습니다
getRange 부분을 간단히 보면
hide가 0인곳(hide = false)을 내림차순으로 가져오고 (ex : 100 ~ 1)
offset부터 최대 limit까지 가져옴 인데
간단하게 예를 들어보자면
ex1) offset이 1이고 limit이 4이면 100부터 97까지
ex2) offset이 4이고 limit이 8이면 97부터 89까지
추가로 db.run(), db.get()등 메소드 괄호 내부에 `~ ${param} ~` 이런식으로 넣으면
에러가 발생해서 따로 sql 필드를 만들어서 넣어줘야되는것 같습니다..
(이거 몰라서 내가 뭘 잘못했지 하면서 시간낭비 + 자괴감이 많이 발생했습니다..)
routes > index
const express = require('express');
const router = express.Router();
const db = require('../db/db_helper')
const validateData = (data, type) => {
if (typeof data != type || typeof data == 'undefined' || data === '') {
console.log('Failed 1', {
1: typeof data != type,
2: typeof data == 'undefined',
3: data === ''
})
return false
}
if (typeof data == 'object' && Object.keys(data).length == 0) {
console.log('Failed 2', {
1: typeof data == 'object',
2: Object.keys(data).length == 0
})
return false
}
return true
}
router.get('/task', async (req, res) => {
console.log('get all tasks')
const pageNo = req.query.pageNo
const pageSize = req.query.pageSize ?? 12
let list
let totalCount
console.log('start')
try {
totalCount = await db.getLength() ?? 0
} catch (error) {
return res.send({ data: error, code: -1 })
}
if (!pageNo) {
try {
list = await db.getAllTasks()
} catch (error) {
return res.send({ data: error, code: -1 })
}
res.send({ data: list, code: 1, currentPage: -1, totalCount: totalCount })
} else {
// 전체 페이지수가 요청수보다 적을 때
if (pageSize > totalCount) {
try {
list = await db.getAllTasks()
} catch (error) {
return res.send({ data: error, code: -1 })
}
return res.send({ data: { list: list, currentPage: Number(pageNo), totalCount: totalCount }, code: 1 })
}
try {
list = await db.getRange((pageNo - 1) * pageSize, pageSize)
} catch (error) {
return res.send({ data: error, code: -1 })
}
res.send({ data: { list: list, currentPage: Number(pageNo), totalCount: totalCount }, code: 1 })
}
})
router.get('/task/:no', async (req, res) => {
let task
try {
task = await db.getSingleTask(req.params.no)
} catch (error) {
return res.send({ data: error, code: -1 })
}
console.log('get task', task)
if (task) {
res.send({ data: task, code: 1 })
} else {
res.send({ data: "No data", code: -1 })
}
})
router.post('/task/add', async (req, res) => {
const data = req.body
console.log('task add', data)
if (validateData(data.title, 'string') && validateData(data.day, 'string') && validateData(data.reminder, 'boolean')) {
let id
try {
id = await db.getLength() ?? 1
} catch (error) {
return res.send({ data: error, code: -1 })
}
const newTest = { id: id + 1, ...data }
let isDone
try {
isDone = await db.insert(newTest)
} catch (error) {
return res.send({ data: error, code: -1 })
}
if (isDone) {
res.send({ data: newTest, code: 1 })
} else {
res.send({ data: `Request failed. (DB insert failed)`, code: -1 })
}
} else {
res.send({ data: `Request failed. (${JSON.stringify(data)})`, code: -1 })
}
})
router.post('/task/delete', async (req, res) => {
const data = req.body
console.log('task delete', data)
let task
try {
task = await db.getSingleTask(data.id)
} catch (error) {
return res.send({ data: error, code: -1 })
}
if (validateData(task, 'object')) {
let isDone
try {
isDone = await db.updateTask('hide', true, task.id)
} catch (error) {
return res.send({ data: error, code: -1 })
}
if (isDone) {
res.send({ data: task.id, code: 1 })
} else {
res.send({ data: `Request failed. (DB update failed)`, code: -1 })
}
} else {
res.send({ data: `Request failed. (${JSON.stringify(data)})`, code: -1 })
}
})
router.post('/task/toggle', async (req, res) => {
const data = req.body
console.log('task toggle', data)
let task
try {
task = await db.getSingleTask(data.id)
} catch (error) {
return res.send({ data: error, code: -1 })
}
if (validateData(task, 'object')) {
let isDone
try {
isDone = await db.updateTask('reminder', !task.reminder, task.id)
} catch (error) {
return res.send({ data: error, code: -1 })
}
if (isDone) {
res.send({ data: task.id, code: 1 })
} else {
res.send({ data: `Request failed. (DB update failed)`, code: -1 })
}
} else {
res.send({ data: `Request failed. (${JSON.stringify(data)})`, code: -1 })
}
})
module.exports = router
db helper에 만든 형식에 맞춰서 수정을 조금(아마도 많이..) 해줬는데
여기는 크게 달라지는 부분이 없으니 get task부분만 조금 보고 넘어가자면
쿼리스트링을 사용할 수 있게 만들었는데
사용 가능한것은 두가지로 pageNo, pageSize입니다
그리고 db에 저장되어있는 length를 한번 가져와서
요청한 사이즈보다 length가 적으면 전부다 보여주게 만들었는데
생각해보니 pageNo에 이상한 값 들어가도 무조건 다 들고오게 했는데
아마도 변경해야될것 같습니다
추가로 try catch를 안해주면 task/a 같이 이상한 값(?)이 들어오면
에러를 뿌리면서 서버가 죽는데, 이부분을 처리해주기 위해 해봤습니다
server
const express = require('express')
const app = express()
const cors = require('cors')
const router = require('./routes')
require('./db/db_helper')
const port = process.env.PORT || 8080
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(cors())
app.use('/api', router)
// 8000 포트로 서버 오픈
app.listen(port, () => {
console.log(`start! express server on port ${port}`)
})
서버는 db helper를 require을 사용해서 가져오면서
db create를 해주고 router를 이용해서 /api를 사용할 수 있게 만들었습니다
백단은 많이 안해봐서 아직 미숙하고 계정관련 처리는 아직 안해봤지만
백엔드의 컨셉을 이해하는정도(?)는 해본것 같고 하면서 재밌게 했었던것 같습니다
'WEB' 카테고리의 다른 글
React - Kakaomap example (0) | 2022.02.19 |
---|---|
React - html, css album page clone (0) | 2022.01.08 |
React, Node - Rest API with sqlite3 (beginner) - 2 (0) | 2022.01.08 |
개발환경 셋팅 - Vs code extension(Web), 단축키 변경 (0) | 2021.11.20 |
개발환경 셋팅 - Windows에서 Node .zip 원하는 경로에 설치 (0) | 2021.11.20 |