학습 기록/데브코스 웹 풀스택 4기

백엔드 기초: 객체, map, req.params

romi__ 2024. 9. 2. 18:07

/date 24.09.02.

 /* 공부하며 정리한 내용이니 정확하지 않을 수 있습니다. 잘못된 내용은 댓글로 알려주세요!*/

 

 

📌

자바스크립트는 특징이 있습니다. const, params를 문자열로 받지만, 그렇게 해서 받은 문자열이 숫자로 이루어졌다면 숫자처럼 알아서 변환하여 계산해 주곤 합니다. 다른 언어에서는 통하지 않는 부분이니 parseInt를 사용하는 버릇을 들이도록 합시다.

if ((req.params.n - 10) > 0) {
	console.log("url로 전달받은 숫자가 10보다 크네요")
} //정상작동: 문자열을 숫자처럼 알아서 바꿔서 계산

let number = parseInt(req.params.n) - 10
//parseInt: 문자열을 숫자로 변환

 

 

📌

그럼 req.params를 사용하는 것을 연습해 보겠습니다.

 

유튜브를 보다 보면 영상마다 주소가 복잡하게 다른 것을 알 수 있습니다. 유튜브 영상의 주소처럼 URL이 바뀌도록 설정해 보겠습니다.

app.get('/:nickname', function(req, res) {
	res.json({
    	channel: req.params.nickname
    })
})

 

url의 마지막 / 뒤에 붙는 문자열을 nickname으로 받습니다. json을 통해 그 nickname을 화면에 뿌려 줍니다. 약간 간결하게 고도화를 진행해보면 아래와 같습니다.

 

app.get('/:nickname', function(req, res) {
	//바뀔 가능성이 없는 부분
    const param = req.params
    
    res.json({
    	channel: param.nickname
    })
})

 

req.params는 반복해서 사용함과 동시에 바뀔 가능성이 거의 없는 부분이라 param 안에 넣어 사용해 보았습니다. nickname 부분에 제 블로그 명을 넣어서 실습해 보았더니 아래와 같은 결과를 볼 수 있었습니다.

 

 

유튜브 영상의 주소를 살펴보다 보면, URL 중간에 물음표가 포함되어 있는 것을 볼 수 있습니다. 이건 왜 뜨는걸까요? 또 타임라인 링크를 복사하면 & 연산자 이후 t=(숫자)s가 붙은 것을 볼 수 있습니다. 대충 재생 시점이라고 예측은 됩니다.

 

하나의 데이터가 아니라 여러 데이터를 던질 때 URL에 물음표가 사용됩니다. 즉, 이건 쿼리 스트링으로 파라미터 값을 받는다는 의미가 됩니다.

 

app.get('/watch', function(req, res) {
	const q = req.query
    console.log(q)
    res.json({
    
    })
})

 

이런 코드를 작성하고 실행시킨 후, 주소창엔 http://localhost:3000/watch?v=romiwaves_ts&t=1920을 입력하였습니다.

 

위 두 줄은 오타입니다(멋윽)

 

그랬더니 v와 t의 데이터를 로그로 찍어주는군요. q는 이미 json 형태를 갖추고 있기 때문에 q를 통째로 돌려줘 보겠습니다.

 

app.get('/watch', function(req, res) {
	const q = req.query
    console.log(q)
    res.json(q)
})

 

이렇게 하면 되겠죠? 좀 더 보기 좋게 영상 코드와 타임라인을 각각 표시해 보겠습니다.

app.get('/watch', function(req, res) {
	const q = req.query
    res.json({
    	영상코드: q.v,
        타임라인: q.t
    })
})

 

 

와앙~ 제대로 작동합니다.

 

 

📌

그런데 위와 같은 화면을 만들 때 아래처럼 코드를 작성하여도 정상적으로 작동합니다.

app.get('/watch', function(req, res) {
	const {v, t} = req.query
    res.json({
    	영상코드: v,
        타임라인: t
    })
})

 

오잉? 이게 무슨 일일까요? 비구조화에 대해 알아볼 필요가 있습니다.

 

평소 array를 사용할 때라면 이렇게 썼을 겁니다.

const array = [1,2,3,4,5]

const num1 = array[0]
const num4 = array[3]

console.log(num1) //1
console.log(num4) //4

 

이런 과정... 솔직히 귀찮습니다. 타이핑해야 하는 코드가 왜 이렇게 길고 많나요? 이 과정을 좀 더 빠르고 편하게 할 수 있도록 자바스크립트가 제공해 주는 문법이 바로 비구조화입니다.

 

const array = [1,2,3,4,5]
const [num2, num3] = array

console.log(num2) //1
console.log(num3) //2

 

이렇게 비구조화를 진행하면 array 순서대로 num2, num3 값을 배분할 수 있습니다. 즉, 배열의 비구조화는 객체와는 상관없이 인덱스 값을 갖고 있기 때문에 그 순서대로 배치가 되게 됩니다. 따라서 원하는 값이 있다면 배열의 순서를 맞춰 주면 됩니다.

 

const array = [1,2,3,4,5]
const [ , num2, num3, , num5] = array

console.log(num2) //2
console.log(num3) //3
console.log(num5) //5

 

이렇게 말이죠!

 

 

📌

그러면 객체를 만들어서 API 테스트를 해보도록 하겠습니다. 서버가 닉네임에 대한 데이터를 갖고 있다고 치겠습니다.

const express = require('express')
const app = express()

let youtuber1 = {
    channelTitle : "롬이세요",
    subscriber : "600만명",
    videos : "900개"
}

let youtuber2 = {
    channelTitle : "로미인디요",
    subscriber : "102만명",
    videos : "5992개"
}

let youtuber3 = {
    channelTitle : "romiwaves",
    subscriber : "39만명",
    videos : "8개"
}

app.get('/:nickname', function(req, res) {
	const {nickname} = req.params
    
    if (nickname == "romromrom") {
    	res.json(youtuber1)
    } else if (nickname == "itsromi") {
    	res.json(youtuber2)
    } else if (nickname == "romiwaves") {
    	res.json(youtuber3)
    }
})

app.listen(3000)

 

유튜버의 nickname을 주소에 붙여서 접속 시 객체 데이터가 화면에 뿌려집니다. 아래 화면처럼 말이죠.

 

 

만약 객체로 저장되지 않은 유튜버의 닉네임을 포함한 주소로 접속한다면 어떻게 될까요? 화면이 넘어가지 않습니다. 서버가 대응을 하지 못하는 것입니다. 이러한 상황은 개발자가 예상하지 못한 에러입니다. 예외에 대한 처리가 필요합니다.

 

const express = require('express')
const app = express()

let youtuber1 = {
    channelTitle : "롬이세요",
    subscriber : "600만명",
    videos : "900개"
}

let youtuber2 = {
    channelTitle : "로미인디요",
    subscriber : "102만명",
    videos : "5992개"
}

let youtuber3 = {
    channelTitle : "romiwaves",
    subscriber : "39만명",
    videos : "8개"
}

app.get('/:nickname', function(req, res) {

    const {nickname} = req.params

    if (nickname == "romromrom") {
        res.json(youtuber1)
    } else if (nickname == "itsromi") {
        res.json(youtuber2)
    } else if (nickname == "romiwaves") {
        res.json(youtuber3)
    } else {
    	res.json({
        	message: "채널에 등록되지 않은 유튜버입니다."
         }) //예외 처리
    }
})

app.listen(3000)

 

이렇게 하면 등록되지 않은 nickname을 주소에 붙여서 접속하더라도 서버가 대응할 수 있습니다.

 

 

📌

잠시 네이밍 케이스를 정리하고 넘어가겠습니다.

  • 파일, 폴더
    • [kebab-case] 알파벳 소문자 사용, 하이픈(-)으로 단어 연결
    • [snake_case] 알파벳 소문자 사용, 두 단어 사이를 이어줄 때 하이픈이 아니라 언더바(_) 사용
    • 둘 중 어떤 것을 사용해도 괜찮지만 통일하는 것이 중요
  • 변수, 함수: [camelCase] 두 개 이상의 단어를 합쳐서 쓸 땐, 두 번째 단어의 첫 글자를 대문자로
  • 클래스: [PascalCase] 첫 글자도 대문자

 

 

📌

Map에 대해 살펴보겠습니다. json은 애당초 Map, 즉 key-value 형태입니다.

 

let db = new Map()
//map을 데이터베이스 대신으로 사용할 것
db.set(키, 벨류) //키로 벨류를 찾을 수 있는 한 쌍을 저장

 

그럼 db가 어떻게 생겼는지 봅시다.

 

let db = new Map()

db.set(1, "NoteBook")
db.set(2, "Cup")
db.set(3, "Chair")

console.log(db)

 

1은 키, NoteBook은 벨류입니다. 이렇게 코드를 작성한 결과는 아래와 같습니다.

 

 

그럼 key 값을 통해 value를 꺼내오려면 어떻게 해야 할까요? 아래처럼 코드를 작성하면 됩니다.

 

console.log(db.get(1))

 

1이라는 key 값을 이용해 NoteBook이라는 value를 꺼내 올 수 있었습니다.

 

그렇다면 이쯤에서 고도화를 진행해 봅시다. URL로 1을 받으면 NoteBook을, 2를 받으면 Cup을, 3을 받으면 Chair를 돌려주려면 어떻게 해야 할까요?

 

코딩에 앞서서 Map이라는 객체는 키값으로 숫자 1과 문자 1을 구분합니다. 따라서 문자열이 들어오면 문자열 값으로 결과를 찾아내겠죠. 그래서 숫자로 바꿔 주는 절차가 필요합니다.

 

const express = require('express')
const app = express()
app.listen(1234)

app.get('/:id', function(req, res) {
	let {id} = req.params
    id = parseInt(id)
    
    res.json({
    	id: id,
        productName: db.get(id)
    })
})

let db = new Map()
db.set(1, "NoteBook")
db.set(2, "Cup")
db.set(3, "Chair")

 

 

제대로 작동하는 것을 볼 수 있습니다. 그럼 만약, 4, 5, 6, 7, ... 처럼 키로 존재하지 않는 숫자를 넣으면 어떻게 될까요?

 

 

저는 하나를 해도 확실한 게 좋아서 왕창 큰 숫자를 넣어 보았습니다. 음, {"id" : ~}의 형태로 화면에 뿌려지는 것은 문제없이 출력되는데, productName은 나오지 않습니다. 당연합니다. 해당하는 값이 없기 때문입니다. 즉 이러한 경우는 요청한 경우에 대한 리스폰스가 정상적이지 않은 경우이므로 예외 처리가 필요합니다.

 

const express = require('express')
const app = express()
app.listen(1234)

app.get('/:id',function(req, res) {
    let {id} = req.params
    id = parseInt(id)

    if (db.get(id) == undefined) {
        res.json({
            message : "없는 상품입니다."
        })
    } else {
        res.json({
            id: id,
            productName: db.get(id)
        })
    }
})

let db = new Map()

db.set(1, "NoteBook") 
db.set(2, "Cup")
db.set(3, "Chair")

 

id가 undefined라면 메세지를 띄우도록 예외 처리를 해 주었습니다.

 

 

제대로 작동하는군요! 야호!

 

 

/*사족입니다*/

  • 비구조화부터 살짝 혼미했는데 잘 이겨낸 나 자신에게 박수를...! 이게 뭐지? 싶다가도 어느 순간 아 이게 어떤 부분에서 쓰이겠구나 짐작하다 보면 이해가 빨라진다. 역시 무조건 부딪혀 봐야 한다.