날씨 open api 사용해서 개발하기 - 1 (요청, 응답 명세 정리)

ZOO4WE·2024년 5월 2일
0

프로젝트

목록 보기
2/2
post-thumbnail

시작하기에 앞서

날씨와 대기 정보를 제공하는 개인 프로젝트를 진행 중이다. 이른바 뛰까(dduikka). 한참 러닝을 하던 시기에 가졌던 불편함에서 시작된 프로젝트다. 그래서 날씨와 대기 정보를 제공해주는 것이 중요해서 포스팅을 하게 되었다.

사용할 http client는 feign client 이다. 하나의 요청으로 두개의 날씨 요청 api 중 하나를 동적으로 조회해오는 것이 목표다. 예를 들어, 기상청 api로 날씨를 조회하다 오류가 발생해서 다른 날씨 api로 호출하는 방식이다.

잡설은 그만하고 날씨 open api를 활용하는 단계를 밟아보자.

날씨 open api 결정

우선 유명한 날씨 open api는 세가지다. 세가지 모두 무료로 api를 제공한다.

  1. 기상청 api (구 동네예보 조회 서비스)
  2. 아큐웨더
  3. OpenWeather

결정 시에 고려해야 할 점은 api를 call할 수 있는 횟수, 금액, 제공하는 api의 종류다.
먼저 결과를 말하자면 3번을 뒤늦게 알게 된 관계로, 나는 1번과 2번을 사용했다. (아큐웨더 누구 코에 붙이는 call 수인지 모르겠음)
이제 각각의 홈페이지에 들어가, api key를 발급 받는다. 해당 과정은 어렵지 않기 때문에 생략하겠다.

예보 api 결정하기

예보 api를 결정해야 하는 이유는 사이트마다 여러개의 예보 api를 제공하기 때문이다. 아래는 무료 기준으로 사용할 수 있는 예보 api다.

기상청

  • 초단기실황조회
    • 요청한 시간(정각 기준)에 대한 예보를 제공한다.
  • 초단기예보조회
    • 요청한 시간 기준으로 1시간 간격으로 총 6시간의 예보까지 제공한다.
  • 단기예보조회
    • 최근 3일간의 예보를 제공한다.

아큐웨더

  • 일일 예보
    • 1일 예보
    • 5일 예보
  • 시간별 예보
    • 1시간당 예보
    • 12시간당 예보

나는 우선 기상청의 초단기실황조회 api와 아큐웨더의 1시간당 예보를 선택하였다. 왜냐하면 뛰는 사람 입장에선 지금의 날씨가 필요하다고 느꼈기 때문이다. 만약 앞으로의 날씨 현황도 알아야 한다면 기상청의 단기예보조회와 아큐웨더의 5일 예보를 선택하지 않을까 싶다.

요청, 응답 메시지 명세 정리 및 테스트

우선 외부와 통신하는 케이스는 요청, 응답의 명세 정리가 필수다. 그래야만 내 프로젝트의 맥락에 맞게 응답 데이터를 변환할 수 있기 때문이다. 또한 나는 하나의 요청을 통해 동적으로 호출할 open api를 결정할 생각이었고, 이때 다형성을 활용하려면 추상화가 필수이기 때문에 명세화를 잘 해두어야만 했다.

여담인데, 전직장에서 개발한 프로그램의 90%가 외부 채널과 통신 해야하는 케이스였던 덕분에 좋은 습관을 들일 수 있었던 것 같다.

기상청 명세

요청 url : http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst

요청 메시지 명세

항목명(영문)항목명(국문)항목크기항목구분샘플데이터항목설명
serviceKey인증키1001인증키(URL Encode)공공데이터포털에서 발급받은 인증키
numOfRows한 페이지 결과 수4150한 페이지 결과 수 Default: 10
pageNo페이지 번호411페이지 번호Default: 1
dataType응답자료형식40XML요청자료형식(XML/JSON)Default: XML
base_date발표일자8120210628‘21년 6월 28일발표
base_time발표시각41050005시 발표* 하단 참고자료 참조
nx예보지점 X 좌표2155예보지점의 X 좌표값*별첨 엑셀 자료 참조
ny예보지점 Y 좌표21127예보지점의 Y 좌표값*별첨 엑셀 자료 참조

응답 메시지 명세

항목명(영문)항목명(국문)항목크기항목구분샘플데이터항목설명
numOfRows한 페이지 결과 수4150한 페이지당 표출데이터 수
pageNo페이지 번호411페이지 수
totalCount데이터 총 개수1011데이터 총 개수
resultCode응답메시지 코드2100응답 메시지코드
resultMsg응답메시지 내용1001NORMAL SERVICE응답 메시지 설명
dataType데이터 타입41XML응답자료형식 (XML/JSON)
baseDate발표일자8120210628‘21년 6월 28일 발표
baseTime발표시각61050005시 발표
fcstDate예보일자8120210628‘21년 6월 28일 예보
fcstTime예보시각4106006시 예보
category자료구분문자31TMP자료구분코드 * 하단 코드값 정보 참조
fcstValue예보 값2121 하단 코드값 정보 참조
nx예보지점 X 좌표2155입력한 예보지점 X 좌표
ny예보지점 Y 좌표21127입력한 예보지점 Y 좌표

자료구분문자(category)

예보구분항목값항목명단위압축bit수
초단기실황T1H기온10
 RN11시간 강수량mm8
 UUU동서바람성분m/s12
 VVV남북바람성분m/s12
 REH습도%8
 PTY강수형태코드값4
 VEC풍향deg10
 WSD풍속m/s10

응답 코드

  • 기상청은 http status는 200이지만, 별도로 제공하는 응답 코드를 통해 에러 유무를 확인해야 한다.
에러코드에러메세지설명
00NORMAL_SERVICE정상
01APPLICATION_ERROR어플리케이션 에러
02DB_ERROR데이터베이스 에러
03NODATA_ERROR데이터없음 에러
04HTTP_ERRORHTTP 에러
05SERVICETIME_OUT서비스 연결실패 에러
10INVALID_REQUEST_PARAMETER_ERROR잘못된 요청 파라메터 에러
11NO_MANDATORY_REQUEST_PARAMETERS_ERROR필수요청 파라메터가 없음
12NO_OPENAPI_SERVICE_ERROR해당 오픈API서비스가 없거나 폐기됨
20SERVICE_ACCESS_DENIED_ERROR서비스 접근거부
21TEMPORARILY_DISABLE_THE_SERVICEKEY_ERROR일시적으로 사용할 수 없는 서비스 키
22LIMITED_NUMBER_OF_SERVICE_REQUESTS_EXCEEDS_ERROR서비스 요청제한횟수 초과에러
30SERVICE_KEY_IS_NOT_REGISTERED_ERROR등록되지 않은 서비스키
31DEADLINE_HAS_EXPIRED_ERROR기한만료된 서비스키
32UNREGISTERED_IP_ERROR등록되지 않은 IP
33UNSIGNED_CALL_ERROR서명되지 않은 호출
99UNKNOWN_ERROR기타에러

기상청 테스트

요청

결과

  • 한 페이지의 결과 수(numOfRows)를 20개로 요청해도 총 8개(totalCount)만 조회된다. 결국 예보는 시간당 category 개수만큼 조회된다는 뜻이다.
{
  "response": {
    "header": {
      "resultCode": "00",
      "resultMsg": "NORMAL_SERVICE"
    },
    "body": {
      "dataType": "JSON",
      "items": {
        "item": [
          {
            "baseDate": "20240502",
            "baseTime": "0600",
            "category": "PTY", // 강수형태
            "nx": 55,
            "ny": 127,
            "obsrValue": "0"
          },
          {
            "baseDate": "20240502",
            "baseTime": "0600",
            "category": "REH", // 습도
            "nx": 55,
            "ny": 127,
            "obsrValue": "91"
          },
          {
            "baseDate": "20240502",
            "baseTime": "0600",
            "category": "RN1", // 1시간 강수량
            "nx": 55,
            "ny": 127,
            "obsrValue": "0"
          },
          {
            "baseDate": "20240502",
            "baseTime": "0600",
            "category": "T1H", // 기온
            "nx": 55,
            "ny": 127,
            "obsrValue": "12.2"
          },
          {
            "baseDate": "20240502",
            "baseTime": "0600",
            "category": "UUU", // 동서바람성분
            "nx": 55,
            "ny": 127,
            "obsrValue": "-0.1"
          },
          {
            "baseDate": "20240502",
            "baseTime": "0600",
            "category": "VEC", // 풍향
            "nx": 55,
            "ny": 127,
            "obsrValue": "22"
          },
          {
            "baseDate": "20240502",
            "baseTime": "0600",
            "category": "VVV", // 남북바람성분
            "nx": 55,
            "ny": 127,
            "obsrValue": "-0.4"
          },
          {
            "baseDate": "20240502",
            "baseTime": "0600",
            "category": "WSD", // 풍속
            "nx": 55,
            "ny": 127,
            "obsrValue": "0.5"
          }
        ]
      },
      "pageNo": 1,
      "numOfRows": 20,
      "totalCount": 8
    }
  }
}

아큐웨더 명세

요청 url : http://dataservice.accuweather.com/forecasts/v1/hourly/1hour/{locationKey}
AccuWeather의 무료 요금제는 말했드싱 매일 50번의 요청만 가능하다. 아큐웨더를 사용하려면 그들의 Location API와 Forecast API를 사용해야 한다. 일일 50개 트래픽으로 location api도 호출하고 forecast api도 호출하라는건 사실상 별로 못한다고 보면 된다. (그냥 아큐웨더말고 오픈웨더 쓰는 거 추천)

요청 메시지 명세

NameDescription
locationKeylocation key provided by accu weather
apikeyProvided API Key.
languageString indicating the language in which to return the resource
detailsBoolean value specifies whether or not to include full details in the response.
metricBoolean value specifies whether or not to display metric values.

응답 메시지 명세

  • details를 true로 설정하면 너무 많은 정보를 제공하기 때문에 개인 프로젝트에서 사용하는 명세만 추렸다.
ParameterTypeDescription
DateTimestringDateTime of the forecast, displayed in ISO8601 format.
Temperature.ValuedoubleRounded value in specified units. May be NULL.
RelativeHumidityint32Relative humidity. May be NULL.
Rain.ValuedoubleRounded value in specified units. May be NULL.
Snow.ValuedoubleRounded value in specified units. May be NULL.

응답 코드

  • 여담이지만 아큐웨더는 HTTP status 코드로 error를 리턴해주기 때문에 feign client 사용 시, FeignException으로 예외가 전파됐다.
HTTP CodeDescription
400Request had bad syntax or the parameters supplied were invalid
401Unauthorized. API authorization failed
403Unauthorized. You do not have permission to access this endpoint
404Server has not found a route matching the given URI
500Server encountered an unexpected condition which prevented it from fulfilling the request

아큐웨더 테스트

https://developer.accuweather.com/accuweather-forecast-api/apis/get/forecasts/v1/hourly/1hour/%7BlocationKey%7D

요청

  • Resource URL의 파란 글씨에 집중하자. 해당 식별자는 아큐웨더가 제공하는 location API를 호출하여 나온 location key이다. 서울 기준으로 226081이며, location key가 없으면 예보를 조회할 수 없다.
  • apikey는 패키지 신청 후 발급 받은 apikey를 의미한다. 고유번호로 외부에 유출되지 않게 조심하자.

응답

  • details를 true로 하면 응답이 너무 길어서 false로 설정한 뒤 받은 응답이다.
[
  {
    "DateTime": "2024-05-02T23:00:00+09:00",
    "EpochDateTime": 1714658400,
    "WeatherIcon": 33,
    "IconPhrase": "맑음",
    "HasPrecipitation": false,
    "IsDaylight": false,
    "Temperature": {
      "Value": 14.4,
      "Unit": "C",
      "UnitType": 17
    },
    "PrecipitationProbability": 0,
    "MobileLink": "http://www.accuweather.com/ko/kr/seoul/226081/hourly-weather-forecast/226081?day=1&hbhhour=23&unit=c",
    "Link": "http://www.accuweather.com/ko/kr/seoul/226081/hourly-weather-forecast/226081?day=1&hbhhour=23&unit=c"
  }
]

앞으로

앞으로 작성해야 할 것들이 있다. feign client를 설정하는 것은 이미 충분히 작성된 글들이 많으므로 생략하고 아래 목록을 기록할 예정이다.

  • 다형성을 활용하여 날씨 api를 동적으로 호출
  • 날씨 데이터 캐싱? or DBMS 저장
  • feign client 테스트, 동적 호출 테스트
profile
직장인 K씨의 개발스러운 일일

0개의 댓글