JAVASCRIPT

javascript) 기상청 Open API를 이용한 날씨 위젯 만들기 2

Neda 2022. 8. 13. 00:49

 

 

목표: JAVASCRIPT를 이용해 Open API 요청하고 응답받기

1. fetch를 이용해 Open API 요청하기

 

1.1 변수를 조립해 url 만들기

먼저 weather 폴더를 만들고 > 안에 index.html, index.js, style.css를 생성한다.

index.js 파일을 열어 api 요청 변수를 변수로 만들어 저장하고

const serviceKey ="76zDuaNaxv5VU7qa";
let numOfRows = "12"; // 1시간당 기상 정보가 최저기온,최고기온을 제외하면 12개이므로 12개가 편하다
let pageNo = "1"; // 페이지 번호
let dataType = "JSON"; // 요청자료형식
let base_date = "20220810"; // 발표일자
let base_time = "2300"; // 발표시각
let nx = "10"; // X좌표
let ny = "127"; // Y좌표
let url;
let array_code = {
  POP: { code: "POP", name: "강수확률", unit: "%" },
  PTY: { code: "PTY", name: "강수형태", unit: "코드값" },
  PCP: { code: "PCP", name: "1시간 강수량", unit: "범주 (1 mm)" },
  REH: { code: "REH", name: "습도", unit: "%" },
  SNO: { code: "SNO", name: "1시간 신적설", unit: "범주(1 cm)" },
  SKY: { code: "SKY", name: "하늘상태", unit: "코드값" },
  TMP: { code: "TMP", name: "1시간 기온", unit: "℃" },
  UUU: { code: "UUU", name: "풍속(동서성분)", unit: "m/s" },
  VVV: { code: "WSD", name: "풍속(남북성분)", unit: "m/s" },
  WAV: { code: "WAV", name: "파고", unit: "M" },
  VEC: { code: "VEC", name: "풍향", unit: "deg" },
  WSD: { code: "WSD", name: "풍속", unit: "m/s" },
};

위의 변수들을 조립하여 하나의 url로 만드는 함수 작성한다

function create_url() {
  return (
    "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst?" +
    "serviceKey=" +
    serviceKey +
    "&numOfRows=" +
    numOfRows +
    "&pageNo=" +
    pageNo +
    "&dataType=" +
    dataType +
    "&base_date=" +
    base_date +
    "&base_time=" +
    base_time +
    "&nx=" +
    nx +
    "&ny=" +
    ny
  );
}

 

1.2 만든 url에 fetch()를 통해 요청 보내기

fetch()를 통해 비동기적으로 Open API 응답받기

function load_api() {
  fetch(url) //url에 요청 보내기
    .then((response) => response.json()) //응답이 json
    .then((data) => {
      if (parseInt(data.response.header.resultCode) > 0) { //resultCode가 0보다 크면 에러
        console.error(
          "ERROR: code: " +
            data.response.header.resultMsg +
            "(" +
            data.response.header.resultCode +
            ")"
        );
      }
      result = data.response.body.items.item; //응답에서 api 정보 부분만 가져오기
      //console.dir(result); 값 확인
      for (const element of result) {
        let value;
        array_code[element.category].value = element.fcstValue; //각각 기상 정보를 array_code에 저장
      }
      //console.table(array_code); 값 확인
    });
}

 


 

2. 현재 시간 정보를 이용해 예보 시간 구하기

 

basedate,basetime -> 가장 최근 발표 시각 사용

최저,최고기온 값이 없을 때는 각 시간에 대해 예보 값이 12개이므로

23:10에 발표한 예보 데이터에서 100개를 불러오면

처음부터 12개는 0시에 대한 예보 데이터,

13~24번 째는 1시에 대한 예보 데이터이다

12개를 한 페이지로 정했을 때(numOfRows=12일 때)

pageNo을 바꿀 때마다 해당 시간의 데이터를 바로 가져올 수 있다.

예보 시간은 총 하루 중 8번이며

2시부터 3시간 간격으로 2시, 5시 8시 ... 23시의 8번이고

이를 api로 사용하기 위해서는 2시 10분, 5시 10분, 8시 10분 ... 23시 10분부터 가능하다.

예를 들어 0시~0시59분일 때는 1시의 예보를 사용하려 한다.

가장 최근 예보 발표 시각인 전날 23시를 기준으로

2페이지(1시 예보 데이터)의 데이터를 요청한다.

하지만,

2시~2시10분 사이일 때는 전날 23시에 발표한 예보데이터를 그대로 사용하여 3시 예보 데이터를 가져오고

2시11분~2시59분 사이일 때는 02시에 발표한 예보데이터를 사용 가능하므로 02시 데이터를 사용한다.

  가져올 예보 데이터의
시각
basedate basetime numOfRows pageNo
0시~0시59분 1시 전날  2300 12 2
1시~1시59분 2시 전날 2300 3
2시~2시10분 3시 전날 2300 4
2시11분~2시59분 3시 오늘 0200 1
3시~3시59분 4시 오늘 0200 2
4시~4시59분 5시 오늘 0200 3
5시~5시10분 6시 오늘 0200 4
5시11분~5시59분 6시 오늘 0500 1
6시~6시59분 7시 오늘 0500 2
...          

 

function loadDate() {
  let public_time = new Date();
  let current_time = new Date();
  let diffTime = 0;
  let month = public_time.getMonth();
  // 가장 최근의 base_date, base_time 구하기
  public_time.setHours(public_time.getHours() - 2);
  public_time.setMinutes(public_time.getMinutes() - 10);
  month = `${public_time.getMonth() + 1}`.padStart(2, "0");
  public_time.setHours(parseInt(public_time.getHours() / 3) * 3 + 2);
  public_time.setMinutes(10);
  base_date = `${public_time.getFullYear()}${month}${public_time.getDate()}`;
  base_time = public_time.getHours() * 100;
  base_time = base_time.toString().padStart(4, "0");
  //발표 시각과 현재 시간과의 차이를 구해 pageNo 찾기
  diffTime = (current_time.getTime() - public_time.getTime()) / 60000;
  if (diffTime < 50) pageNo = 1; //2310~2359
  else if (diffTime < 110) pageNo = 2; //00~0:59
  else if (diffTime < 170) pageNo = 3; //1:00~1:59
  else pageNo = 4;
}

참고 사이트)

 

 

Date() 생성자 - JavaScript | MDN

Date 생성자는 시간의 특정 지점을 나타내는 Date 객체를 플랫폼에 종속되지 않는 형태로 생성합니다. Date 객체는 1970년 1월 1일 UTC(국제표준시) 자정으로부터 지난 시간을 밀리초로 나타내는 UNIX

developer.mozilla.org

 


 

3. 현재 내 위치를 이용해 Open API 호출 

현재 위치는 Geolocation API를 이용해 쉽게 찾을 수 있고

현재 위치한 위도와 경도를 알 수 있다. 사용하는 네트워크에 따라 오차가 클 수 있다.

 

HTML Geolocation API

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

getCurrentPosition()을 통해 위치를 찾고 이에 성공했을 경우 콜백으로 success()를 실행한다.

navigator.geolocation.getCurrentPosition(success, error, options);

success()함수에는

현재의 위도와 경도를 가져와 (기상청 api에서 사용하는) nx,ny 좌표로 변환하는 dfs_xy_conv()를 실행하고

위에서 만든 loadDate(), create_url(),load_api()를 실행한다.

function success(pos) {
  var crd = pos.coords;
  let rs = dfs_xy_conv("toXY", crd.latitude, crd.longitude);
  nx = rs.x;
  ny = rs.y;
  console.log("Your current position is:");
  console.log(`Latitude : ${crd.latitude}`);
  console.log(`Longitude: ${crd.longitude}`);
  loadDate();
  url = create_url();
  load_api();
}