나름 제휴 파트에서 사용할 API를 구현을 다 했고 이걸 프로트 JS파일에 데이터를 불러와서 사용해야 하는데
프론트를 해본적이 없어서 감도 안잡혔다...
간만에 말도 안되는 삽질을 오래 하고서 지금은 좀 정리되었지만 다시 생각해도 악몽임
API제작
우선 나는 제휴 페이지를 먼저 만들었다.
제휴 페이지와 소상공인 페이지 디자인이 비슷하고 제휴페이지는 우선 내가 API를 만들어야 하기 때문...
제휴 페이지에서는 학교이름 university_name혹은 university_url을 인자로 받으면 DB에서 해당 대학에 해당하는 제휴 가게 정보를 모두 반환하는 API를 구성하였다.
모델에 만들어놓은 코드는 별로 안어렵고 직전에 올린 포스트에 있는 코드에서 그냥 Partner테이블을 사용한 쿼리문으로만 바꿔준것!
[UniUnity 개발일지] 4. MySQL Table 및 모델 생성
DB 설계할 때 생각지도 못한 부분이 있는데 바로 지도를 사용하려면 테이블에 저장되었는 모든 주소의 (위도, 경도) 값을 함께 저장해야 한다는 것 테스트용 데이터를 DB에 5개 정도 만드는데, 이
ji0hyun.tistory.com
home.ctrl.js
getPartner: async(req,res) => {
const partner = new Partner();
const university_id = await partner.getUniversityID(req.body.university_url);
const university_location = await partner.getUniversityLocation(university_id);
const university_uni = await partner.getPartnerStores(university_id);
const obj = [];
obj.push({latitudeUni: university_location.latitude, longitudeUni: university_location.longitude});
for(let i = 0; i < university_uni.length; i++){
obj.push(university_uni[i]);
}
return res.json(obj);
}
일단 제휴페이지가 어떻게 동작하는지를 살펴보면,
1. http://localhost:3000/partner/university_url롤 접속하면 university_url값을 인자로 받기
=> 이 url값을 받는 건 프론트 단에서 이루어지는거고, 백엔드 API는 이 url을 이미 받아와 인자로 넣는 것부터 구현.
2. university_url을 통해서 university_id 값을 반환함.
=> university_url로 university_id를 반환하는 API를 구현해 놓았다.
2. university_id값을 통해서 해당 대학의 중심좌표를 받아옴
=> 중심좌표 받는 API를 구현해 놓았다.
3. university_id값으로 해당 학교에 해당하는 Partner 테이블의 데이터를 모두 반환.
* 이때 굳이 university_id를 사용하는 이유는 university_id가 Partner테이블에서는 외래키인데, 이 외래키가 참조하는 테이블의 기본키이여야 하기 때문이다.
그렇게 해서 받아온 해당 대학의 중심좌표와 university_location와 university_uni를 하나의 배열에 넣어 반환해준다.
사실 university_location와 university_uni를 각각 반환하는 API가 있는데, 그걸 프론트 단에서 각각 불러와도 되긴한다.
하지만 그럼 fetch함수를 여러번 사용해야 하는데, fetch함수를 여러번 사용할 때마다 데이터를 불러오는 시간과 순서가 좀 어려워지기 때문에 어짜피 같이 사용해야 하는 데이터라면 API구현 시 한번에 반환하는 것이 편리하다.
이번 코드 짜면서 느끼는건데, 프론트에서 fetch함수를 쓰고자 한다면 굳이 여러번 할 필요가 없으면 나누지 말것.
아래는 구현한 API를 사용하여 데이터 호출한 결과

프론트 엔드에서 불러오기
그럼 이제 위에서 만든 API를 프론트에서 불러와 사용해 주어야 한다.
우선 partner/sungshin으로 접속했을 때 이 'sungshin'값을 반환해 주어야 하는데, 아래와 같은 코드로 받아올 수가 있다.
/ university_url 값을 받아오는 함수
function getUniversityUrl() {
// 현재 페이지의 URL에서 경로(pathname) 부분을 추출
const path = window.location.pathname;
// 경로에서 universityUrl 값을 추출
const pathParts = path.split('/');
const universityUrl = pathParts[pathParts.length - 1];
return universityUrl;
}
프론트 코드 전부 다는 아니고 좌표를 받아 지도에 마커로 띄우는 코드
사실 이외의 코드는 변수 선언 하는 등의 코드라 큰 의미는 없음.
getUniversityUrl함수로 partner/sungshin, partner/konkuk으로 접속하면 각각 'sungshin'과 'konkuk'을 추출해 string으로 반환함.
// university_url 값을 받아오는 함수
function getUniversityUrl() {
// 현재 페이지의 URL에서 경로(pathname) 부분을 추출
const path = window.location.pathname;
// 경로에서 universityUrl 값을 추출
const pathParts = path.split('/');
const universityUrl = pathParts[pathParts.length - 1];
return universityUrl;
}
function partnerLoad(){
const universityUrl = getUniversityUrl();
const req = {
university_url:universityUrl
};
fetch(`http://localhost:3000/getPartner`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(req),
})
.then((res) => res.json())
.then(res => {
center.push(res[0]);
// 지도의 중심좌표 변경
setCenter(map,parseFloat(center[0].latitudeUni),parseFloat(center[0].longitudeUni));
// 새로운 객체 생성
for(let i = 1; i < res.length; i++){
const obj = {
storeID: res[i].storeID,
storeName: res[i].storeName,
store_location: res[i].store_location,
university_id: res[i].university_id,
content: res[i].content,
startDate: res[i].startDate,
endDate: res[i].endDate
};
stores.push(obj);
// 객체의 좌표 부분은 따로 저장
positions.push(new kakao.maps.LatLng(parseFloat(res[i].latitude),parseFloat(res[i].longitude)));
for (let i = 0; i < positions.length; i ++) {
// 마커를 생성합니다
let marker = new kakao.maps.Marker({
map: map, // 마커를 표시할 지도
position: positions[i] // 마커의 위치
});
// 마커 click, mouseover, mouseout 시에 이벤트 발생
kakao.maps.event.addListener(marker, 'click', function(){
for(let i = 0; i < storeInfoTextBox.length; i++){
storeInfoTextBox[i].style.display = "block";
}
storeName.innerHTML = stores[i].storeName;
storeAdr.innerHTML = stores[i].store_location;
partnerContent.innerHTML = stores[i].content;
eventDate.innerHTML = stores[i].startDate + " ~ " + stores[i].endDate;
});
}
};
})
.catch(error => {
console.error("Error: ", error);
})
}
window.addEventListener('DOMContentLoaded', partnerLoad);
완성한 제휴가게 페이지


저기 옆에 가게 목록은 html에서 div태그 안에 ul태그 하나만 선언해 놓은 후 이 ul에다가 동적 목록 li를 추가하는 코드를 js에서 만들어주었다.
아래는 관련 코드
for (let i = 0; i < positions.length; i ++){
// 목록에 동적으로 추가
const li = document.createElement("li");
li.setAttribute('id',stores[i].storeName);
const textNode = document.createTextNode(stores[i].storeName);
li.appendChild(textNode);
document.getElementById('storeList').appendChild(li);
li.addEventListener('click',function(){
for(let j = 0; j < storeInfoTextBox.length; j++){
storeInfoTextBox[j].style.display = "block";
}
storeName.innerHTML = stores[i].storeName;
storeAdr.innerHTML = stores[i].store_location;
partnerContent.innerHTML = stores[i].content;
eventDate.innerHTML = stores[i].startDate + " ~ " + stores[i].endDate;
})
}
이 코드는for문을 제외한 상태로 위에 partnerLoad에 마커 생성하는 코드 밑에 바로 넣어줘도 무관하다.
이 코드가 있으면 제휴가게 목록을 저장해놓은 stores안에서 모든 가게의 이름을 꺼내와 순서대로 표시한다.
fetch함수 사용?
프론트엔드 코드를 만들면서 가장 삽질했던 부분은 다름이 아니라 fetch함수 사용이 요상하게 이루어졌다는 점.
이게 해결방법이 뚜렷하지 않은데, 우리 팀 같은 경우는 다른 팀원이 로그인 구현할 시 사용한 모듈 하나가 내 코드의 fetch함수의 작동을 막아 버리지 않나.... 참 답답함
물론 내가 잘 모르는 거 일 수도 있지만 생각보다 프론트 JS파일에서는 예상치도 못한 이유 때문에 실행에 문제가 생길 수도 있는데 또 그걸 자세히 안알려줘서 엄청 고생했었다.
아래에 적을 내용은 fetch함수 뿐만이 아니라 JS에서 코드가 잘 안돌아갈 때 이것중에 하나일 확률이 높아서(나는 그랬다) 그냥 기록해볼겸 적어본다.
1. fetch함수의 url을 잘못 적음
: fetch함수의 경우 제일 처음 인자로 사용하고자 하는 API의 url을 작성해줘야 하는데, 이 주소가 "http://~"와 같이 http부터 시작하는 주소를 올바르게 작성해주어야 한다.
2. 변수 선언 및 값 할당 시 var,let,const 중 어떤 걸로 선언할 거고 했는지 확인하기
: 나도 배웠지만 여전히 자주 어려운 개념. 예를 들어 const의 경우 처음 선언하고 할당한 값을 변경할 수가 없는데 const로 선언한 변수의 값을 바꿔주려 하면 안바뀜! 그래서 나 같은 경우는 let 을 주로 사용하려고 했는데, 이것도 참 되는 경우가 있고 안되는 경우가 있는데 너무 복잡해서 그냥 어려운 부분은 console로 찍어주면서 확인했다. 제일 좋은 방법은 그 변수를 선언한 블로이나 함수 단위 안에 변수를 사용하는 코드를 같이 만들어 주는 것!
3. 코드 순서가 잘못되었음
: 나는 1학년 때 JavaScript를 배울 때 JS는 처음 모든 코드를 읽어오고 실행하기에 순서가 섞여도 괜찮다고 배운 것 같은데.. 아무튼 사용하려는 코드들의 순서에 따라 어떤 함수는 실행이 안될 수도 있다. 특히 A,B함수 순서대로 실행해 주었는데 A함수에서 사용한 fetch에서 문제가 생기면 그 뒤 친구들도 실행이 안될 수 있다는 점.
4. 복사 붙여넣기 과정 중 어떤 변수나 코드 일부분이 생략됨
: 뭐.... 다른 사람들 코드를 가져다 쓰는 경우도 있지만 나 같은 경우에는 구현하려는 페이지들에서 중복되는 기능은 당연히 한 곳에서 작성한 코드를 그대로 가져와 사용하였다. 근데 이 과정에서 누락된 변수나 코드가 있다면 실행이 안되므로 꼼꼼하게 확인을 한 번하는게 좋다.
추가로 나 같은 경우에는 내가 만드는 페이지는 그 페이지에서 사용하는 API도 내가 구현하고 그 API를 사용하여 프론트 구현도 내가 했기 때문에 API에서 오류가 났나? 라는 생각도 했었다. 근데 이 API의 경우는 Postman으로 잘 돌아가는 걸 확인할 수 있어서 AP문제가 아니라는 걸 확신하고 프론트에서 오류 찾기에 집중했었다. API가 의심갈 때는 Postman으로 한 번씩 확인해주는 것도 좋을 것 같다. (그렇지만 Postman도 종종 오류가....)
프론트 오류는... 종종 사막에서 바늘 찾는 기분이었습니다... 그런데 결국 내문제 아닌걸 확인했때... 배신감과 안도감... 참 좋은 경험이네요....
그렇지만 덕분에 코드는 깔끔해짐
'개발일지' 카테고리의 다른 글
| [UniUnity 개발일지] 4. MySQL Table 및 모델 생성 (0) | 2023.07.06 |
|---|---|
| [UniUnity 개발일지] 3. 공공데이터 오픈 API 사용하기 1 (0) | 2023.07.06 |
| [UniUnity 개발일지] 2. Node.js 서버에 카카오 지도 API연결하기 (0) | 2023.07.06 |
| [UniUnity 개발일지] 1. node.js로 서버 구축 시작하기 (0) | 2023.07.06 |