require("dotenv").config();
const express = require("express");
const axios = require("axios");
const app = express();
const PORT = process.env.PORT || 3000;
const API_KEY = process.env.API_KEY;
app.set("view engine", "ejs");
app.get("/", (req, res) => {
res.render("index", { places: [], message: null });
});
app.get("/search-place", async (req, res) => {
const query = req.query.query;
const googlePlacesUrl = `https://maps.googleapis.com/maps/api/place/textsearch/json?query=${query}®ion=kr&language=ko&key=${API_KEY}`;
try {
const response = await axios.get(googlePlacesUrl);
console.log("API Response:", response.data);
// API 응답이 성공적이고 결과가 있을 때
if (response.data.status === "OK" && response.data.results.length > 0) {
// 장소의 상세 정보 요청
const placeDetails = await getPlaceDetails(response.data.results);
res.render("index", { places: placeDetails, message: null });
} else {
res.render("index", { places: [], message: "검색 결과가 없습니다." });
}
} catch (error) {
console.error("API Error:", error);
res.render("index", {
places: [],
message: "검색 중 오류가 발생했습니다.",
});
}
});
// 장소의 상세 정보를 비동기적으로 가져오는 함수
const getPlaceDetails = async (places) => {
try {
const placeDetailsPromises = places.map(
(place) =>
axios
.get(
`https://maps.googleapis.com/maps/api/place/details/json?place_id=${place.place_id}&language=ko&key=${API_KEY}`
)
.then((response) => response.data.result)
);
return await Promise.all(placeDetailsPromises);
} catch (error) {
console.error("Failed to fetch place details:", error);
return [];
}
};
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Place Search</title>
</head>
<body>
<h1>장소 검색</h1>
<form action="/search-place" method="GET">
<input
type="text"
name="query"
placeholder="장소를 입력하세요"
required
/>
<button type="submit">검색</button>
</form>
<% if (message) { %>
<p><%= message %></p>
<% } %> <% if (places && places.length > 0) { %>
<h2>검색 결과</h2>
<ul>
<% places.forEach((place) => { %>
<li>
<strong><%= place.name %></strong><br />
<p><%= place.formatted_address %></p>
</li>
<% }); %>
</ul>
<% } %>
</body>
</html>
<h1>장소 검색</h1>
<form action="/search-place" method="GET">
<input
type="text"
name="query"
placeholder="장소를 입력하세요"
required
/>
<button type="submit">검색</button>
</form>
장소 입력을 받는 input
여기서 작성된 input value는 서버("/search-place")로 넘어감
if (response.data.status === "OK" && response.data.results.length > 0)
"OK" 는 요청이 성공적으로 처리되었고, 결과가 정상적으로 반환되었을 때다
response.data.results.length > 0 여기는 누가봐도 데이터가 존재하는지 체크하는 부분
이 두 조건을 모두 충족했을 때 조건문이 실행된다
조건문 내부
const placeDetails = await getPlaceDetails(response.data.results);
상세 정보 요청 함수의 return 값을 변수에 담는다
getPlaceDetails() 를 들여다보자
const getPlaceDetails = async (places) => {
try {
const placeDetailsPromises = places.map(
(place) =>
axios.get(
`https://maps.googleapis.com/maps/api/place/details/json?place_id=${place.place_id}&language=ko&key=${API_KEY}`
)
.then((response) => response.data.result)
);
return await Promise.all(placeDetailsPromises);
} catch (error) {
console.error("Failed to fetch place details:", error);
return [];
}
};
places 파라미터로 Object 뭉탱이(response.data.results)를 받는다
placeDetailsPromises 변수에 요소들의 세부 정보 mapping 한다
mapping이 끝나면 placeDetailsPromises 를 return 한다
res.render("index", { places: placeDetails, message: null });
서버에서 작업이 끝난 뭉탱이를 클라이언트로 전송한다
<% if (message) { %>
<p><%= message %></p>
<% } %> <% if (places && places.length > 0) { %>
<h2>검색 결과</h2>
<ul>
<% places.forEach((place) => { %>
<li>
<strong><%= place.name %></strong><br />
<p><%= place.formatted_address %></p>
</li>
<% }); %>
</ul>
<% } %>
클라이언트에서 EJS 문법을 이용해서 서버에서 받은 값들을 화면에 표시한다
정상적으로 데이터가 넘어왔다면 message 는 빈 상태일 것
places 가 제대로 넘어왔는지 if문으로 검사를 거친 후
places 에 foreach 반복문을 적용해서 모든 값을 순차적으로 화면에 뿌려준다
하루 종일 한 결과물이 이거다
이제 장소 검색 단 하나 구현했다
내일은 소요 시간을 구현해야 한다
다 하고나니 문제가 생겼다...
현재 한국에서 구글맵은 대중교통 경로만 지원하고 나머지는 지원하지 않는다고 한다
아 다시 만들어야되네