Code States 44
의사코드의 중요성
becky(지은)
2023. 4. 11. 09:30
처음에 (my agora states) 파일을 봤을때 생소한 코드가 너무 많아서
어떻게 코드를 시작해야 할지 감도 잡기 힘들었다
그래서 챗 지피티에게 코드 한줄 한줄씩 물어보며 주석을 달기 시작했다
특히 어떤 개념을 이해하기 어려우면 예시도 추가적으로 물어보면서 접근했다
A와 B의 차이점을 묻는 질문도 큰 도움이 된다
내 친구 챗 gpt ...ㅎ
이번에 느낀점은 아무리 생소하고 어려운 코드라도
의사코드를 작성한다면 이해하지 못할게 없다는 것이다.
잘 모를 수록 멀뚱멀뚱 코드만 보지 말고 뭐라도 쳐야 한다!!
(my agora states)
const express = require('express');//express 라이브러리를 불러와, express 변수에 할당하고
const app = express(); //express 어플리케이션을 생성하고, app변수에 할당
const cors = require('cors'); //cors를 활성화하기위해 cors라이브러리를 불러옴
const morgan = require('morgan'); //morgan 라이브러리를 불러옴
// morgan 미들웨어가 세팅되어 있습니다.HTTP 요청 logger를 편리하게 사용할 수 있는 미들웨어 입니다.
app.use(morgan('tiny'));
// 'morgan'은 http 요청에 대한 로그(컴퓨터 기록)를 생성하는 라이브러리로, 'tiny'는 로그의 출력방식을 지정하는 인자
// tiny는 매우 간단한 형태의 로그를 생성
// 로그: GET /users 304 2.582 ms - -
// 각각 cors()와 express.json()이라는 미들웨어 등록(중간다리)
app.use(cors());
// cors 라는 미들웨어를 등록함, 이 cors 미들웨어는 다른 라우터들보다 먼저 실행
// 모든 라우터들이 cors처리(다른 출처의 리소스 받아오기 가능)
// TODO: Express 내장 미들웨어인 express.json()을 적용합니다.
app.use(express.json({strict: false}));
//express.json()미들웨어를 사용하면 클라이언트가 보낸 JSON 데이터를 파싱하는 역할
//이때, {strict: false}옵션으로 전달하면 엄격한 모드를 해제
//JSON 데이터를 보내는 클라이언트가 엄격한 JSON 형식을 따르지 않더라도 서버에서 파싱할 수 0
const port = 4000;
const discussionsRouter = require('./router/discussions');
// TODO: app.use()를 활용하여 /discussions 경로로 라우팅합니다.
app.use('/discussions',discussionsRouter);
app.get('/', (req, res) => {
// 서버 상태 확인을 위해 상태 코드 200과 함께 응답을 보냅니다.
res.status(200).send('fe-sprint-my-agora-states-server');
});
const server = app.listen(port, () => {
console.log(`[RUN] My Agora States Server... | http://localhost:${port}`);
});
module.exports.app = app;
module.exports.server = server;
(my agora states)
const { agoraStatesDiscussions } = require("../repository/discussions");
const discussionsData = agoraStatesDiscussions;
const discussionsController = {
//'/'경로로 get 요청이 들어왔을때, findAll함수를 사용하여 요청처리
findAll: (req, res) => {
// 1. TODO: 모든 discussions 목록 응답 // 예시) get /discussions?q=nodejs&page=2
/*req.query 형태
{
q: 'nodejs',
page: '2'
}
*/
// 요청의 쿼리의 키가 존재하지 않을때, 모든 디스커션데이터를 보여주기
if(Object.keys(req.query).length === 0){
return res.status(200).json(discussionsData)
}
},
findById: (req, res) => {
// '/:id' 경로로 get 요청이 들어왔을때, findById라는 함수를 사용하여 요청처리
// 2. TODO: 요청으로 들어온 id와 일치하는 discussion 응답
//예시)http://localhost:3000/users/123 이면
//req.params 는 {id: '123'}
//먼저, req.params의 id 속성을 추출해서 선언한다
const {id} =req.params
const filteredData = discussionsData.filter((discussion)=>{
return discussion.id === Number(id) // 콜백함수 {} 안에서 return 꼭쓰기
})
//discussionsData 에 필터 메서드를 걸어 디스커션의 id와 입력된 id가 같은 데이터들로 새로운 배열을 만듦
// 이때, 입력된 id가 문자열로 인식되니 숫자로 바꿔주기
//req.params.id가 string 형태로 들어온다. Number로 변환
if(filteredData.length === 0){
return res.status(404).json('아이디를 찾을 수 없음')
}else{
return res.status(200).json(filteredData[0])
}
//필터된 데이터가 없다면, 배열이니 0으로
// 아이디를 찾을 수 없다고 json형태로 상태코드와 함께 응답
//필터되어서 나온 게 있다면 // 나온게 있다면, 어차피 같은 id가 없으니 배열 중 0번째를 뽑기
//[0]으로 뽑아와야만 출력이 된다.
},
//[PUT] /discussions/:author
// 요청된 author값과 동일한 author값을 가진 디스커션 데이터를 요청된 body 데이터로 수정
replaceByAuthor: (req, res) => {
const {author} = req.params
const bodyData = req.body
const beUpdatedIdx = discussionsData.findIndex((discussion)=>{
return discussion.author === author
})
const updatedDiscussion = {...discussionsData[beUpdatedIdx],...bodyData}
discussionsData.splice(beUpdatedIdx, 1, updatedDiscussion);
return res.status(200).json(updatedDiscussion);
}
}
module.exports = {
discussionsController,
};
//첫 번째 수정된 부분은 res.status(200).JSON(discussionsData)에서 JSON 대문자를 소문자 json으로 변경한 것입니다.
//json은 res 객체의 메서드가 아니기 때문에 대문자로 작성하면 실행되지 않습니다.
/*if(Object.keys(req.query).length === 0)와 if(req.query.query === undefined)는 다르게 동작합니다.
if(Object.keys(req.query).length === 0)은 req.query 객체에 속성이 하나도 없을 때 true를 반환합니다. 따라서 쿼리 스트링이 전혀 없는 경우에 사용할 수 있습니다.
반면에 if(req.query.query === undefined)은 query라는 이름의 속성이 없을 때 true를 반환합니다. 이 경우 쿼리 스트링이 있더라도 query라는 이름의 속성이 없으면 true를 반환하므로 원하는 대로 동작하지 않습니다.
따라서 if(req.query.query === undefined)는 쿼리 스트링에서 query라는 이름의 속성을 확인하는 경우에만 사용해야 합니다. 만약 query가 아닌 다른 속성을 확인하려면 그 속성의 이름을 사용해야 합니다.
따라서 if(Object.keys(req.query).length === 0)를 사용하는 것이 더 안전합니다.
위의 코드에서 'if(Object.keys(req.query).length === 0)' 대신 'if(req.query === undefined)' 라고 쓰면 안될까?
if(Object.keys(req.query).length === 0)과 if(req.query === undefined)는 다르게 동작합니다.
if(Object.keys(req.query).length === 0)은 req.query 객체에 속성이 하나도 없을 때 true를 반환합니다. 반면에 if(req.query === undefined)은 req.query 객체 자체가 undefined일 때 true를 반환합니다.
따라서 if(req.query === undefined)는 req.query 객체가 undefined일 때만 작동하므로 쿼리 스트링이 전혀 없는 경우에는 작동하지 않습니다.
따라서 if(Object.keys(req.query).length === 0)를 사용하는 것이 더 안전합니다.
Regenerate response */
(statesairline server)
const airports = require('../repository/airportList');
module.exports = {
// [GET] /airport?query={query} 요청을 수행합니다.
// 공항 이름 자동완성 기능을 수행합니다!
findAll: (req, res) => {
if (req.query.query !== undefined) {
console.log(req.query.query);
const filteredAirports = airports.filter((airport) => {
return airport.code.includes(req.query.query.toUpperCase());
});
return res.status(200).json(filteredAirports);
}
res.json(airports);
}
};
//위의 코드는 findAll 함수를 정의하고,
//router.get('/', findAll); 에 보이듯이 get 메서드에 의한 라우팅을 처리하는 코드다
//이 코드는 클라이언트로 부터 'GET/ airport' 요청이 들어오면 실행된다
// 먼저 함수 내부에서 쿼리스트링 파라미터인 query 값을 검사합니다
// 이때 req.query가 아닌 req.query.query를 쓰는 이유는 'req.query'는 클라이언트에서 요청을 보낼때 쿼리스트링에
//대한 데이터를 포함하고 있슴 대략적으로 이런 { query: 'NY' } 형태의 객체를 포함함
//그래서 req.query.query를 사용함으로써, query 키에 대응하는 값을 가져옴
//만약 query 값이 있으면 airport 배열에서 query 값과 관련된 공항을 찾아서
//filteredAirports라는 새로운 배열을 만듦
//여기서 공항의 코드값을 기준으로 판단함
//이를통해, 클라이언트에서는 '/airport?query=NY' 와 같은 요청을 보내면,
//서버에서는 'NY' 관련된 공항정보를 찾아 json 형식으로 반환합니다
(statesairline server)
//Array.prototype.filter()는 조건에 맞는 모든 요소를 추출하여 새로운 배열을 만드는 반면,
//Array.prototype.find()는 조건에 맞는 첫 번째 요소만을 추출함
//Array.prototype.findIndex()는 콜백함수는 만족하는 첫번째 요소의 인덱스를 반환하는 메소드
const flights = require('../repository/flightList');
const fs = require('fs');
const { filter } = require('../repository/flightList');
module.exports = {
// [GET] /flight
// 요청 된 파라미터 departure_times, arrival_times 값과 동일한 값을 가진 항공편 데이터를 조회합니다.
// 요청 된 파라미터 departure, destination 값과 동일한 값을 가진 항공편 데이터를 조회합니다.
//findAll 함수는 /flight 엔드포인트에 대한 get 요청 처리
// 요청에 포함된 쿼리 파라미터를 기반으로 항공편 데이터 검색
findAll: (req, res) => {
const { departure_times, arrival_times, destination, departure } = req.query;
//이런 속성이 요청 객체인 req.query에 다 포함되었다고 선언하는 것
// 왜 이딴식으로 선언을 했나 싶지만 이것은 req.query라는 객체에서 속성을 추출해서 변수선언, 구조분해할당으로 선언한것
//const departure_times = req.query.departure_times;
//const arrival_times = req.query.arrival_times;
//const destination = req.query.destination;
//const departure = req.query.departure;
// 'req.query' 는 쿼리 파라미터에 대한 정보, ? 뒤에 나오는 key=value를 쌍, 객체 형태임
// TODO:
if(departure_times !== undefined && arrival_times !== undefined){
const filteredFlights = flights.filter((flight)=>{ //콜백함수가 참이 되는 새로운 요소만 새로운 배열로 반환한다
return flight.departure_times === departure_times && flight.arrival_times === arrival_times
});
return res.status(200).send(JSON.stringify(filteredFlights));
}
if(destination !== undefined && departure !== undefined){
const filteredFlights = flights.filter((flight)=>{ //콜백함수가 참이 되는 새로운 요소만 새로운 배열로 반환한다
return flight.destination === destination && flight.departure === departure
});
return res.status(200).send(JSON.stringify(filteredFlights));
}
return res.status(200).send(JSON.stringify(flights));
//만약 쿼리파라미터가 제공되지 않으면, 함수는 모든 항공편을 검색하여 flights 배열을 응답본문으로 보냄
},
// [GET] /flight/:uuid
// 요청 된 uuid 값과 동일한 uuid 값을 가진 항공편 데이터를 조회합니다.
//findById 함수는 /flight/:uuid라는 엔드포인트에 대한 get 요청을 처리
// 요청에 포함된 UUID 파라미터를 기반으로 항공편 데이터를 검색함
findById: (req, res) => {
const { uuid } = req.params;
//req.params는 객체로 uuid라는 속성을 지닌다는 것을 선언한 것(구조분해 할당))
// TODO:
if(uuid !== undefined){
const filteredFlights = flights.filter((flight)=>{
return flight.uuid === uuid //return 값이 참이 되는 새로운 배열을 추출
});
return res.status(200).send(JSON.stringify(filteredFlights));//필터된 배열을 JSON 형식으로 바꿔줌
}
return res.status(200).send(JSON.stringify(flights)); //만약 req.params의 uuid 속성이 존재하지 않는다면, 그냥 전체 flights 배열을 내보냄
},
// Advanced
// [PUT] /flight/:uuid 요청을 수행합니다.
// 요청 된 uuid 값과 동일한 uuid 값을 가진 항공편 데이터를 요청된 Body 데이터로 수정합니다.
// 기존의 값은 그대로 두고, 해당되는 uuid 값만 교체하기, 그리고 그렇게 교체한 값 리턴
update: (req, res) => {
const { uuid } = req.params;
const bodyData = req.body;
// TODO:
const beUpdatedIdx = flights.findIndex((flights)=>flights.uuid ===uuid)
const updatedFlight = { ...flights[beUpdatedIdx], ...bodyData }; //최종적으로 업데이트된 flight
flights.splice(beUpdatedIdx, 1, updatedFlight);
//flights 배열에서 beUpdatedIdx 인덱스에 위치한 기존 항공편 정보 객체를 1개만큼 삭제한 후,
//해당 인덱스에 새롭게 업데이트된 객체(updatedFlight)를 추가하여 대체(replace)
/*const updatedFlight = { ...flights[beUpdatedIdx], ...bodyData } 코드는,
flights 배열에서 beUpdatedIdx 인덱스에 위치한 객체와 bodyData 객체를 합쳐서
새로운 객체를 생성합니다. 이 새로운 객체는 updatedFlight 상수에 할당됩니다. 기존의 객체가 아닌 새로운 객체를 생성하기 때문에 인덱스가 겹치는 문제는 발생하지 않습니다.
즉, updatedFlight 객체는 flights 배열에서 찾은 해당 인덱스의 객체와 bodyData 객체의 속성을
모두 갖는 새로운 객체가 됩니다. 이후 flights.splice(beUpdatedIdx, 1, updatedFlight)
코드를 통해, beUpdatedIdx 인덱스의 객체를 updatedFlight 객체로 교체합니다.
따라서 flights 배열에서 해당 인덱스의 객체는 새로운 객체로 대체되며,
겹치는 문제는 발생하지 않습니다. */
/* 파일 수정 */
// const jsonData = JSON.stringify(flights);
// fs.writeFileSync(
// `${__dirname}/../repository/flightList.js`,
// `module.exports = ${jsonData}`
// );
return res.status(200).json(updatedFlight);
}
};
//Array.prototype.filter()는 조건에 맞는 모든 요소를 추출하여 새로운 배열을 만드는 반면,
//Array.prototype.find()는 조건에 맞는 첫 번째 요소만을 추출함
//Array.prototype.findIndex()는 콜백함수는 만족하는 첫번째 요소의 인덱스를 반환하는 메소드