본문 바로가기
[ 프로젝트 ]/미니 프로젝트 스터디

< 날씨별 추천 옷차림 >

by 디디 ( DD ) 2023. 2. 23.

 

 

 

 세 번째 미니 프로젝트 스터디의 주제는 API를 활용한 웹페이지 만들기!

수업 때 배운 걸 직접 써먹어 보는 거라 왠지 두근두근했다.

 

 

 제일 처음 떠오른 아이디어는 '꽃가루 알림'이었다. 개인적으로 꽃가루 알레르기가 있어 평소 필요하다고 느끼던 거였다. 먼저, 공공데이터포털(https://www.data.go.kr/index.do)에 들어가 관련 API를 찾아 활용 신청을 했다. 그리고 데이터가 어떻게 받아와지는지 확인하기 위해 예제를 보고 포스트맨을 통해 요청을 보내보았다. 그런데 지금은 관련 데이터의 제공 기간이 아니어서 응답 메시지를 제대로 확인할 수가 없었다. 배우는 입장에선 직접 눈으로 응답 메시지를 확인하고 데이터를 가공하는 부분이 필요할 것 같아 결국 주제를 바꾸기로 했다.

 

 

 다음으로는 활용할 API를 먼저 정하고 주제를 생각해 보기로 했다.

많은 사람들이 활용하여 관련 예시가 많은 기상청 단기예보한국환경공단의 대기오염정보를 받아오는 것이 좋을 것 같아 이 두 가지 API의 활용을 신청했다.

 

 

 그리고 어떻게 활용을 할까 생각하다 떠오른 것이 예전에 봤던 '온도별 옷차림 자료'였다. 인터넷 뉴스 기사에서는 통계청이 발표한 자료라고 했는데, 찾아보니 그냥 인터넷에 떠도는 자료들인 것 같았다. 그래서 이들을 참고하여 내 생각이 좀 들어간 <날씨별 추천 옷차림>을 만들어보기로 했다. 

 

 

 확실히 많은 사람들이 이용하는 API라 그런지 자료가 잘 정리되어 있었다. 

 

 

 여기서 고려해야 할 것은 예보지점을 X, Y좌표로 넣어 요청해야 한다는 점과 발표 시각이 하루 여덟 번으로 정해져 있다는 것이었다. 기상청이 제공한 워드 파일에 '단기예보 지점 좌표(X, Y)위치와 위경도 간의 전환 C 프로그램 예제'가 있었는데, 처음엔 그걸 발견하지 못해 좌표를 변환할 수 있는 방법을 구글링했고, 활용할 수 있는 자료를 발견하였다.

 

 

https://gist.github.com/fronteer-kr/14d7f779d52a21ac2f16

 

기상청 격자 <-> 위경도 변환

GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

이 함수를 활용하여 위경도를 받아와 X, Y좌표로 변환해서 요청 URL에 넣어줄 수 있었다.

 

 

그리고 날짜와 시간은 이렇게 요청 형식에 맞게 가공해서 넣어 주었다.

 

let date = new Date();
const hours = ('0' + date.getHours()).slice(-2);
const minutes = ('0' + date.getMinutes()).slice(-2);
const time = Number(hours + minutes);  //현재 시간
let standardTime = ''; 
if(210 <= time && time < 510){
    standardTime = '0200';
} else if(510 <= time && time < 810){
    standardTime = '0500';
} else if(810 <= time && time < 1110){
    standardTime = '0800';
} else if(1110 <= time && time < 1410){
    standardTime = '1100';
} else if(1410 <= time && time < 1710){
    standardTime = '1400';
} else if(1710 <= time && time < 2010){
    standardTime = '1700';
} else if(2010 <= time && time < 2310){
    standardTime = '2000';
} else if(2310 <= time){
    standardTime = '2300';
} else {
    date = new Date(new Date().setDate(new Date().getDate() - 1));  //어제
    standardTime = '2300';
}
const year = date.getFullYear();
const month = ('0' + (date.getMonth() + 1)).slice(-2);
const day = ('0' + date.getDate()).slice(-2);
const base_date = `${year}${month}${day}`;  //출력 예시 => '20230212'
const base_time = `${standardTime}`;  //발표 기준 시간으로 변환

 

날짜가 넘어가는 지점에서 조금 애를 먹었다. 

 

 

 

 그다음 코드값을 확인하여 필요한 데이터를 받았다. 1시간 기온(TMP)을 받아와 각 온도마다 다른 이미지가 뜨도록 코드를 작성해 주었다. 기준은 28도, 23도, 20도, 17도, 12도, 9도, 5도로 설정하였다. 각 이미지는 통일된 느낌의 무료 자료를 찾기 어려워 pixabay, unsplash의 사진들을 참고해서 직접 간단하게 그린 것이다.

 

 

 

 다음으로 이 페이지가 외출 전에 확인하는 페이지라고 가정했을 때 더 필요한 것이 뭘까 생각을 해봤는데, 우산이나 마스크를 챙겨야 할지 알려주는 것이 좋을 것 같았다. 그래서 단기예보에서 강수확률(POP)을 받아와 50% 이상이면 우산 이모지(☂️)가, 이하면 무지개 이모지(🌈)가 나타나도록 해주었다. 

 

 

 미세먼지 데이터는 대기오염정보 API를 통해 받아왔다. 이 API는 각 측정소를 기준으로 자료를 보내주기 때문에 현재 위치를 활용하기 어려웠다. 전체 측정소 자료를 모두 넣어준 후 현재 위치의 위경도를 받아와 직선거리를 비교해서 가장 가까운 측정소를 찾을 수 있을 것 같긴 한데, 기한 안에 구현하기 어려울 것 같아 일단 종로구를 기준으로 데이터를 받았다. pm10의 Grade 정보를 받아왔으며, 각 Grade가 의미하는 바는 아래와 같다. 

 

 

참고로 pm10은 미세먼지, pm2.5는 초미세먼지를 의미한다고 한다. 제공된 워드 파일을 보면 초미세먼지 데이터도 활용할 수 있는 것 같은데, 실제 응답메시지상에는 관련 정보가 없어 미세먼지 데이터만 이용했다. 그렇게 Grade 값이 3 이상이면 마스크 쓴 이모지(😷)가, 2 이하면 웃는 이모지(😊)가 나타나게 해주었다.

 

 

 그런데 페이지를 배포하는 중 문제가 발생했다. 내 컴퓨터에서는 문제가 없었는데, 배포된 페이지에는 API 데이터가 받아와지질 않았다. 에러코드를 읽어보니 Mixed content 에러가 발생했다고 쓰여 있었다. Mixed content 에러란 암호화된 HTTPS 기반의 사이트에서 암호화되지 않은 HTTP 사이트에 요청을 보내 발생하는 문제라고 한다. 해결 방법은 html 파일의 head 부분에 아래와 같은 구문을 적어 넣어 주면 된다.

 

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

 

다행히 이 방법을 통해 문제를 해결할 수 있었다. 

 

 

 

 


 

 

완성된 페이지 보러가기 >>  https://dd-stack.github.io/dress-for-the-weather/

깃허브 리포지토리 (코드) 보러가기 >> https://github.com/dd-stack/dress-for-the-weather

 

시연 화면

 

 

 

● 아쉬운 점

 

 미세먼지 api를 받아올 때 현재 위치 기준으로 정보를 받아오고 싶었는데 그러지 못해 아쉬웠다. 시간이 나면 다시 한번 고민해 봐야겠다. 하는 김에 초미세먼지 정보를 받아올 수 있는 방법도 더 찾아보면 좋을 것 같다. 또, 다 만들고 개발과 관련 없는 친구들에게 보여주었는데, 다양한 코디 자료가 있으면 더 좋을 것 같다는 피드백을 공통적으로 받았다. 추후 이미지 자료를 더 추가해야겠다. 

 아, 그리고 스터디 발표 때 생각지 못한 문제도 발견하였다. 개인적으로 발급받은 API 키값이 노출되지 않게 할 방법도 알아두어야 앞으로 더 큰 프로젝트를 할 때 문제가 없을 것 같다. 

 

 

 

● 느낀 점

 

 일단 시각적인 결과물이 있어 완성하고 꽤 뿌듯했다. 그리고 확실히 직접 필요한 데이터를 받아와 이용해 보니 어떻게 API를 사용해야 할지 좀 더 감이 잡혔다. 이번에 내가 활용한 API들은 요청과 응답의 예시 등 관련 자료들이 꽤 구체적으로 제공되는 것들이었는데, 생각보다 친절하지 않은 API들도 많았다. 그리고 제공하는 주체에 따라 제공되는 방식도 좀 달랐다. 앞으로 다양한 API들을 이용해 보며 나에게 필요한 데이터를 잘 받아와 알맞게 활용할 수 있도록 연습해야겠다. 

 

 

 


 

 

 (2023.08.27 업데이트) 

 

 

 포트폴리오를 정리하면서 미니 프로젝트 스터디 결과물 중 제일 반응이 좋았던 < 날씨별 추천 옷차림 >을 추가하면 좋을 것 같다는 생각이 들었다. 날짜를 보니 이 프로젝트를 만든 지도 벌써 6개월이 지났다. 그렇다 보니 아무래도 부족한 점도, 아쉬운 점도 많아 먼저 간단하게 업그레이드 및 리팩토링을 진행해 보기로 했다. 방향은 내용이나 기능 추가보다는 완성도를 올리는 쪽으로 잡았다. 그렇게 당시 아쉬웠던 점을 참고하여 (1) 현재 위치 기준으로 미세먼지 데이터 받아오기와 (2) API키 숨기기를 해보았다. 

 

 

 먼저, 한국환경공단 대기오염 자료를 자세히 살펴보았는데, 근접 측정소 목록을 조회할 수 있는 api가 있었다. 이를 이용하면 현재 위치와 가장 가까운 측정소 정보를 확인할 수 있으므로, 현재 위치를 기준으로 미세먼지 데이터를 받아올 수 있을 것 같았다. 다만, 자바스크립트로 쉽게 알 수 있는 위/경도가 아닌 TM 측정 방식의 X/Y 좌표가 필요했다. 그래서 추가적으로 활용한 것이 통계지리 정보 서비스의 좌표변환 api (https://sgis.kostat.go.kr/developer/html/newOpenApi/api/develop/dvp.html)이다. 이를 이용하여 WGS84 경/위도(코드: 4326) 중부원점(GRS80)(코드: 5181)으로 변환할 수 있었다. 

 

참고 이미지 (좌표계 코드표)

 

회원 가입을 한 후 사용 가이드에 따라 Access Token을 발급받고, 변환 api를 요청하면 된다. 가이드가 친절해서 어렵지 않게 활용할 수 있었다. 

 

 

 다음으로 하드코딩 되어있던 api 키를 숨기려고 바닐라 자바스크립트 프로젝트에서 환경 변수 쓰는 법을 열심히 찾아봤는데, 보통 env 파일을 이용하려면 빌드 과정이 필요한 것 같았다. 단순한 페이지인데 굳이 리액트 프로젝트로 바꿀 필요는 없을 것 같아 다양한 방법을 시도해 보다가 vite로 vanilla 프로젝트를 만들어 기존코드를 적용시키는 방식으로 목적을 달성할 수 있었다. 

 

 

이 밖에도 아래와 같은 부분이 업데이트되었다. 

 

- 파비콘 추가

- 모바일용 반응형 디자인 적용

- 강수형태 데이터 추가

- 초미세먼지 데이터 추가

- 가독성 향상을 위한 파일 분리 및 코드 정리

 

 

 바닐라 자바스크립트가 꽤 오랜만이라 생각보다 시간이 더 걸렸지만, 기존의 프로젝트를 다듬으면서 그동안 내가 많이 성장했다는 것을 느낄 수 있었다. 또 나중에 보면 엉망이겠지만, 앞서 그냥 넘겨왔던 부분들에 대해서도 다시 한번 생각하고 공부해 볼 수 있었다. 

 

 

 

(+) 무사히 재배포를 하고 다음날, 근접 측정소 목록이 잘 받아와지지 않는 문제가 발생했다. 안 그래도 됐다 안됐다 하는 게 좀 불안하긴 했는데, api 키를 재발급 받아 적용되는 시간이 필요한 것이라고 생각했었다. 그런데 자고 일어나 확인해 보니 아예 기능이 작동하질 않는 것이다. 따로 에러가 나는 게 아니라 200 코드가 오면서 응답 내용에 SERVICE_KEY_IS_NOT_REGISTERED_ERROR 라는 글자가 떴다. 찾아보니 등록되지 않은 서비스키를 이용했을 때 오는 응답이었다. 나와 같은 문제를 겪는 사람들이 많은 것 같았고, url 인코딩 문제일 수도 있다고 해서 이것저것 시도해 보았다. 다시 새로 키를 발급받고 1시간 이상 기다리면 된다는 얘기도 있어서 오래 기다려도 봤다. 결국 이도 저도 안돼서 문의를 남기려고 게시판을 들어갔는데, 거기서 POST 메서드로 보내니 됐다는 글을 보았다. 바로 적용해 보았고, 문제가 해결되었다. 기술문서에 기능 유형이 조회라고 적혀 있기도 했고, api 이름도 getNearbyMsrstnList고, 따로 어떤 메서드를 이용하라는 말이 없어서 당연히 GET 메서드를 써야 할 것이라고 생각했는데, 예상치 못한 문제 해결 방식이었다. 덕분에 또 새로운 걸 배울 수 있었고, 이렇게 내가 도움을 받은 것처럼 나와 같은 문제를 겪는 사람들을 위해 에러 해결 로그를 잘 작성해 두어야겠다는 생각이 들었다. 

 

 

 

 

 

댓글