오늘 해결했어야 하는 문제들은 위와 같았다.
처음에는 내가 서버의 입장이 되어서 코드를 작성해야 한다는 점이 잘 받아들여지지 않아서 한참동안 코드를 읽어봐야 했다.
파일 목록들 중에서 가장 상위에 있는 파일은 app.js라는 파일이고, 그 다음이 라우터들이 담긴 router.js, 그 다음이 controller 함수들이 담긴 js 파일들이었다.
(refactor 과제와 다른 점은 Router라는 개념이 나온다는 건데 이건 결국 파일들을 나눠서 관리하기 위함이다.)
이번에는 과제 시작 전에 코드를 정말 꼼꼼하게 읽어봤다. 중간에 주말이 끼어있기도 해서 코드를 읽어보며 이 코드가 대체 어디에 사용되는 것이며, 어떻게 작동하고 있는지 찬찬히 살펴봤는데 막힘없이 술술 풀지는 못했어도 최소 스터디원이나 페어와 같이 누군가의 설명을 들었을 때 이해가 안 되어서 설명을 이해할 수 없는 악순환은 없었던 것 같다.
코드스테이츠가 제공해준 API 문서를 잘 활용했다. 막연히 API라고 계속해서 이야기를 들었을 때는 그래서 어쩌라는 거지, 그런 생각이 들었는데 문서를 잘 살펴보니 어떤 형식으로 어떻게 응답을 전달해야하는지 등의 내용들이 다 적혀 있더라.
사실 이번 페어 프로그래밍에서는 설명을 많이 해야했었는데, 확실히 내가 제대로 이해하지 못한 부분들에 대해서 설명하는 것은 어렵다고 느껴졌다. 그래서 좀 더 열심히 했던 것 같다. 누군가에게 기대려는 마음 없이 간만에 이렇게 열심히 한 것 같아서 조금 뿌듯하다.
어쨌든 내 힘으로 문제를 다 풀었다고는 할 수 없을 것 같다. 많은 분들의 도움을 받았다. 감사히 생각하며 나도 더 정진해서 도움을 줄 수 있는 사람이 되어야지.
구조분해할당 이녀석이 요물인 것 같은데 내가 잘 활용하지 못하는 것 같다. 잘만 사용하면 나도 고급스러운 코드를 쓸 수 있을 것 같은데...?!
공식 문서를 좀 더 잘 해석했다면...하는 아쉬움도 있다. 아직 공식 문서들의 화법(?)에 익숙하지 않은 탓인 것 같은데, 공식 문서 해부하기 같은 콘텐츠를 만들어 보고 싶기도 하다. (... 시간 있냐..너? ㅋㅋ...)
: StatesAirline 서버 구현 - Express 프레임워크를 이용해 만들고 + 로컬 호스트와 연결하기.
States Airline Server는 클라이언트의 요청에 따라 항공편과 예약 데이터를 조회, 생성, 수정, 그리고 삭제하는 기능을 수행할 수 있어야 함.
서비스에 필요한 미들웨어와 웹 서버를 실행하는 코드가 작성되어 있음.
const express = require("express");
const cors = require("cors");
const app = express();
const port = 3001;
const flightRouter = require("./router/flightRouter");
const bookRouter = require("./router/bookRouter");
const airportRouter = require("./router/airportRouter");
//router 폴더에 들어있는 Router.js 파일들은 각각 airport API, book API, flight API 요청을 수행하는 라우터가 작성되어 있음.
//작성된 라우터 내용을 통해 API 요청을 받을 수 있음.
app.use(cors());
app.use(express.json());
app.use("/flight", flightRouter);
app.use("/book", bookRouter);
app.use("/airport", airportRouter);
//중략
app.listen(port, () => {
console.log(`[RUN] StatesAirline Server... | http://localhost:${port}`);
});
정의된 API 요청을 수행하는 코드를 작성해야 함. (이미 작성되어 있으므로 해당 컨트롤러 내용을 발판삼아 다음 flightController와 bookController를 작성하면 됨.)
[GET] / airport?query={query}
airportController는 GET 요청으로, query라는 이름의 쿼리값으로 들어온 값으로 공항 리스트를 담고 있는 airports라는 배열에서 해당 쿼리의 값(모두 대문자로 바꿔준)이 airports 배열의 각 요소들 내에 존재하는지 filter한 후 해당하는 값들만 반환해 200 상태 코드와 함께 응답을 보낸다.
findAll: (req, res) => {
if (req.query.query !== undefined) {
//query가 존재할 때
console.log(req.query.query);
const filteredAirports = airports.filter((el) => {
//airportList에서 받아온 airports를 필터링한 배열을 filteredAirports에 할당할 것임
return el.code.includes(req.query.query.toUpperCase());
});
return res.status(200).json(filteredAirports);
}
res.json(airports);
},
findAll: (req, res) => {
const { departure_times, arrival_times, destination, departure } =
req.query;
let filteredFlight = flights.slice();
if (req.query.departure_times) {
filteredFlight = filteredFlight.filter((el) => {
return el.departure_times === req.query.departure_times;
});
}
if (req.query.arrival_times) {
filteredFlight = filteredFlight.filter((el) => {
return el.arrival_times === req.query.arrival_times;
});
}
if (req.query.destination) {
filteredFlight = filteredFlight.filter((el) => {
return el.destination === req.query.destination;
});
}
if (req.query.departure) {
filteredFlight = filteredFlight.filter((el) => {
return el.departure === req.query.departure;
});
}
return res.status(200).json(filteredFlight);
},
findById: (req, res) => {
const { uuid } = req.params;
// TODO:
let list = flights.slice();
if (req.params.uuid) {
list = list.filter((el) => {
return el.uuid === req.params.uuid;
});
}
return res.status(200).json(list);
},
update: (req, res) => {
const { uuid } = req.params;
const bodyData = req.body;
// TODO:
let findIndex; //flights 배열의 요소들 중 uuid가 같은 요소의 인덱스를 담을 변수
for (i = 0; i < flights.length; i++) {
if (flights[i].uuid === uuid) {
findIndex = i;
}
}
flights[findIndex] = { ...flights[findIndex], ...bodyData };
//원래 flights[findIndex]의 요소였던 객체를 스프레드 연산자를 이용해 풀어서 새로운 객체 안에 넣고,
// bodyData로 받아온 객체도 풀어서 새로운 객체 안에 넣게 되는데,
//이렇게 되면 뒤에 들어온 객체에 동일한 key가 있을 때 뒤에 들어온 값을 따르게 될 것임.
//자연스럽게 수정이 되는 효과...
return res.status(200).json(flights[findIndex]);
},
자주 등장하는 uuid라는 녀석은 서버단에서 고유한 id를 만들기 위해 대중적으로 사용하는 형식으로 bookController에서는 버전 4를 사용해 고유한 id를 만들어주었다.
1.findAll 함수 : [GET] /book
let booking = [];
//전역 변수
// 전체 예약 데이터를 조회합니다.
findAll: (req, res) => {
return res.status(200).json(booking);
},
// 요청 된 phone과 동일한 phone 예약 데이터를 조회합니다.
findByPhone: (req, res) => {
const { phone } = req.params;
if (phone) {
let data = booking.filter((el) => el.phone === phone);
return res.status(200).json(data);
}
},
// 요청 된 id, phone과 동일한 uuid, phone 예약 데이터를 조회합니다.
findByPhoneAndFlightId: (req, res) => {
const { phone, flight_uuid } = req.params;
// TODO:
if (phone && flight_uuid) {
let data = booking.filter(
(el) => el.phone === phone && el.flight_uuid === flight_uuid
);
return res.status(200).json(data);
}
},
3.create 함수 : [POST] /book
create 함수를 만드는 데 꽤 오랜 시간을 사용했다... 처음에는 API에서 response부분을 제대로 읽지 않아서 booking_uuid라는 변수를 어디에 써야하는지 헤맸다.
response 에는 booking_uuid, flight_uuid, name, phone 네 가지의 항목이 있어야 했고, 요청으로 들어오는 객체 속에는 booking_uuid를 제외한 나머지 값들이 들어온다.
그러면 booking이라는 예약 데이터 객체들을 요소로 가진 배열에 push를 통해 받아온 req.body 객체를 넣어주면 되는데, 그 전에 랜덤한 uuid를 만드는 booking_uuid를 미리 req.body.booking_uuid = bookin_uuid 와 같이 넣어주면 된다.
create: (req, res) => {
const booking_uuid = uuid();
req.body.booking_uuid = booking_uuid;
booking.push(req.body);
return res.status(201).json(booking);
// const {flight_uuid, name, phone} = req.body
// 구조분해할당을 해주면 아래처럼 키 값들을 변수처럼 사용할 수도 있다
// 멋지군. 따로 booking_uuid라는 키 값을 만들어주는 과정이 없어서 편하고 보기 좋은듯.
// const newBook = {
// booking_uuid,
// flight_uuid,
// name,
// phone
// }
// booking.push(newBook);
// res.status(201).json(newBook)},
// 요청 된 id, phone 값과 동일한 예약 데이터를 삭제합니다.
deleteByBookingId: (req, res) => {
const { booking_uuid } = req.params;
// TODO:
if (booking_uuid) {
booking = booking.filter((el) => el.booking_uuid !== booking_uuid);
return res.status(200).json(booking);
}
//booking은 배열
//배열을 순회하면서 booking_uuid가 동일한 객체를 찾는다
//해당 객체를 삭제하면 되는데...
//동일하지 않은 객체들만 filter로 담아주면 되긴 할듯
},
};
const express = require('express')
const app = express()
const port = 3000
const logger1 = (req, res, next) => {
console.log("logger1");
next();
}
const logger2 = (req, res, next) => {
console.log("logger2");
next();
}
const codestates = (req, res) => {
res.send('Hello CodeStates!');
}
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.use(logger1, logger2);
app.get('/codestates', codestates);
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
위 코드에서 app.use(logger1, logger2) 코드가 app.get('/', //생략) 보다 밑에 있기 때문에 미들웨어 적용이 되어있지 않음. 그러므로 GET /요청을 서버에 보내면 "logger1", "logger2"는 콘솔 출력 X
app.get('/codestates', codestates) 코드는 app.use(logger1, logger2)보다 아래에 있기 때문에 미들웨어 적용이되며, GET /codestates요청을 서버에 보내면 "logger1", "logger2"가 콘솔에 출력됩니다.