각진 세상에 둥근 춤을 추자
[API] 3. 기상청 단기예보 조회 서비스 - 공공데이터포털 API 본문
https://www.data.go.kr/index.do
아래 주소를 통해 회원가입 및 로그인 후 기상청_단기예보 API를 활용신청한다.
마이페이지의 활용신청 현황에서 일반 인증키(Encoding)를 복사한다.
해당 화면에서 "상세설명"과 "참고문서"를 참고하여 코드를 작성한다.
해당 화면의 "활용신청 상세기능정보"에서 요청변수에 따른 응답결과를 미리볼 수 있다.
참고로 "초단기예보조회"는 최근 3일 간의 데이터만 제공하기 때문에
base_date(발표시각) 요청 파라미터 값을 오늘 날짜로부터 3일 이내로 변경하여 요청한다.
그럼 다음과 같은 JSON 타입의 결과값을 반환한다.
해당 페이지의 "상세설명"을 통해 요청변수와 출력결과의 이름을 확인할 수 있다.
공공데이터포털 홈페이지에서 제공하는 JavaScript 샘플 코드는 다음과 같다.
'서비스키'에 일반 인증키(Encoding)를 붙여 넣는다.
/* Javascript 샘플 코드 */
var xhr = new XMLHttpRequest();
var url = 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst'; /*URL*/
var queryParams = '?' + encodeURIComponent('serviceKey') + '='+'서비스키'; /*Service Key*/
queryParams += '&' + encodeURIComponent('pageNo') + '=' + encodeURIComponent('1'); /**/
queryParams += '&' + encodeURIComponent('numOfRows') + '=' + encodeURIComponent('1000'); /**/
queryParams += '&' + encodeURIComponent('dataType') + '=' + encodeURIComponent('JSON'); /**/
queryParams += '&' + encodeURIComponent('base_date') + '=' + encodeURIComponent('20210628'); /**/
queryParams += '&' + encodeURIComponent('base_time') + '=' + encodeURIComponent('0600'); /**/
queryParams += '&' + encodeURIComponent('nx') + '=' + encodeURIComponent('55'); /**/
queryParams += '&' + encodeURIComponent('ny') + '=' + encodeURIComponent('127'); /**/
xhr.open('GET', url + queryParams);
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
alert('Status: '+this.status+'nHeaders: '+JSON.stringify(this.getAllResponseHeaders())+'nBody: '+this.responseText);
}
};
xhr.send('');
아래 코드는 주소에 따른 위도, 경도 값을 통해 해당 위치의 현재 기상 정보를 조회한다.
이때, 일단 위도, 경도 값이 아닌 기상 정보 API에서 요구하는 격자 x, y 포인트 값으로 조회한다.
위도, 경도는 이전에 작성했던 카카오 지도의 geocoder에서 추출한다.
let latPoint = ""; // 위도
let lonPoint = ""; // 경도
let xPoint = ""; // 격자 x 포인트
let yPoint = ""; // 격자 y 포인트
// 위도, 경도
let xValue = parseFloat(result[0].x);
let yValue = parseFloat(result[0].y);
latPoint = yValue; // 위도
lonPoint = xValue; // 경도
샘플 코드에 있는 요청 변수에 조회하고자 하는 값을 입력한다.
base_date는 20240117 형식, base_time는 1730 형식, nx와 ny에는 변환된 x, y 포인트 값을 입력해야 한다.
다만 base_time(발표 시각)은 30분 마다 갱신되기 때문에 현재 시각으로부터 30분 이전의 시각을 입력해야 한다.
// 오늘 날짜 구하기
let currentDate = new Date();
let year = currentDate.getFullYear();
let month = ('0' + (currentDate.getMonth() + 1)).slice(-2);
let day = ('0' + currentDate.getDate()).slice(-2);
let formattedDate = year + month + day;
// 현재 시간에서 -30분 시간 구하기 (30분마다 데이터 갱신)
let hours = ('0' + currentDate.getHours()).slice(-2);
let minutes = ('0' + (currentDate.getMinutes() - 30)).slice(-2);
// 만약 minutes가 30보다 작으면 hours에서 1을 빼주기
if (currentDate.getMinutes() < 30) {
hours = ('0' + (currentDate.getHours() - 1)).slice(-2);
minutes = ('0' + (currentDate.getMinutes() + 30)).slice(-2);
}
let formattedTime = hours + minutes;
// 좌표를 격자 x,y point로 바꾸기
let result = dfs_xy_conv("toXY", latPoint, lonPoint);
console.log("X:", result.x, "Y:", result.y);
xPoint = result.x;
yPoint = result.y;
위도, 경도를 x, y 격자 포인트로 변경하는 JavaScript 코드 함수는 다음과 같다.
/** 위도, 경도를 x,y 격자 포인트로 변경 */
var RE = 6371.00877; // 지구 반경(km)
var GRID = 5.0; // 격자 간격(km)
var SLAT1 = 30.0; // 투영 위도1(degree)
var SLAT2 = 60.0; // 투영 위도2(degree)
var OLON = 126.0; // 기준점 경도(degree)
var OLAT = 38.0; // 기준점 위도(degree)
var XO = 43; // 기준점 X좌표(GRID)
var YO = 136; // 기1준점 Y좌표(GRID)
// LCC DFS 좌표변환 ( code : "toXY"(위경도->좌표, v1:위도, v2:경도), "toLL"(좌표->위경도,v1:x, v2:y) )
function dfs_xy_conv(code, v1, v2) {
// LCC DFS 좌표변환을 위한 기초 자료
var DEGRAD = Math.PI / 180.0;
var RADDEG = 180.0 / Math.PI;
var re = RE / GRID;
var slat1 = SLAT1 * DEGRAD;
var slat2 = SLAT2 * DEGRAD;
var olon = OLON * DEGRAD;
var olat = OLAT * DEGRAD;
var sn = Math.tan(Math.PI * 0.25 + slat2 * 0.5) / Math.tan(Math.PI * 0.25 + slat1 * 0.5);
sn = Math.log(Math.cos(slat1) / Math.cos(slat2)) / Math.log(sn);
var sf = Math.tan(Math.PI * 0.25 + slat1 * 0.5);
sf = Math.pow(sf, sn) * Math.cos(slat1) / sn;
var ro = Math.tan(Math.PI * 0.25 + olat * 0.5);
ro = re * sf / Math.pow(ro, sn);
var rs = {};
if (code == "toXY") {
rs['lat'] = v1;
rs['lng'] = v2;
var ra = Math.tan(Math.PI * 0.25 + (v1) * DEGRAD * 0.5);
ra = re * sf / Math.pow(ra, sn);
var theta = v2 * DEGRAD - olon;
if (theta > Math.PI) theta -= 2.0 * Math.PI;
if (theta < -Math.PI) theta += 2.0 * Math.PI;
theta *= sn;
rs['x'] = Math.floor(ra * Math.sin(theta) + XO + 0.5);
rs['y'] = Math.floor(ro - ra * Math.cos(theta) + YO + 0.5);
}
else {
rs['x'] = v1;
rs['y'] = v2;
var xn = v1 - XO;
var yn = ro - v2 + YO;
ra = Math.sqrt(xn * xn + yn * yn);
if (sn < 0.0) - ra;
var alat = Math.pow((re * sf / ra), (1.0 / sn));
alat = 2.0 * Math.atan(alat) - Math.PI * 0.5;
if (Math.abs(xn) <= 0.0) {
theta = 0.0;
}
else {
if (Math.abs(yn) <= 0.0) {
theta = Math.PI * 0.5;
if (xn < 0.0) - theta;
}
else theta = Math.atan2(xn, yn);
}
var alon = theta / sn + olon;
rs['lat'] = alat * RADDEG;
rs['lng'] = alon * RADDEG;
}
return rs;
}
준비된 요청 변수를 통해 현재 위치에 따른 기상 정보를 조회한다.
var xhr = new XMLHttpRequest();
var url = 'http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtFcst'; /*URL*/
var queryParams = '?' + encodeURIComponent('serviceKey') + '='+'app key'; /*Service Key*/
queryParams += '&' + encodeURIComponent('pageNo') + '=' + encodeURIComponent('1'); /* 페이지 번호 */
queryParams += '&' + encodeURIComponent('numOfRows') + '=' + encodeURIComponent('1000'); /* 한 페이지 결과 수 */
queryParams += '&' + encodeURIComponent('dataType') + '=' + encodeURIComponent('JSON'); /* 응답자료형식 */
queryParams += '&' + encodeURIComponent('base_date') + '=' + encodeURIComponent(formattedDate); /* 발표일자 */
queryParams += '&' + encodeURIComponent('base_time') + '=' + encodeURIComponent(formattedTime); /* 발표시각 */
queryParams += '&' + encodeURIComponent('nx') + '=' + encodeURIComponent(xPoint); /* 예보지점 X 좌표 */
queryParams += '&' + encodeURIComponent('ny') + '=' + encodeURIComponent(yPoint); /* 예보지점 Y 좌표 */
xhr.open('GET', url + queryParams);
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
console.log("Success!");
// JSON 파싱
var jsonResponse = JSON.parse(this.responseText);
// 필요한 정보 추출
var items = jsonResponse.response.body.items.item;
console.log("items length: " + items.length);
for (var i = 0; i < items.length; i++) {
var item = items[i];
console.log("item: " + JSON.stringify(item));
console.log("자료구분코드: " + item.category);
console.log("예보일자: " + item.fcstDate);
console.log("예보시각: " + item.fcstTime);
console.log("예보값: " + item.fcstValue);
}
} else {
console.log("Error: " + this.status);
}
}
};
xhr.send('');
예를 들어 콘솔창에 로그가 다음과 같이 뜬다.
해당 category값과 fcstValue 값을 활용한다.
코드값은 참고 문서를 통해 확인한다.
위 로그의 경우, category "SKY"는 "하늘 상태" 코드를 나타내며 fcstValue "4"는 "흐림"을 나타낸다.
'프로젝트 > API' 카테고리의 다른 글
[API] JAVA 단일 문자 전송 API(SMS API) (1) | 2024.09.12 |
---|---|
[API] 2. 기상청 단기예보 조회 서비스 - KakaoMap API (0) | 2024.01.17 |
[API] 1. 기상청 단기예보 조회 서비스 - 화면 구현 (0) | 2024.01.16 |