날씨와 대기 정보를 제공하는 개인 프로젝트를 진행 중이다. 이른바 뛰까(dduikka). 한참 러닝을 하던 시기에 가졌던 불편함에서 시작된 프로젝트다. 그래서 날씨와 대기 정보를 제공해주는 것이 중요해서 포스팅을 하게 되었다.
사용할 http client는 feign client
이다. 하나의 요청으로 두개의 날씨 요청 api 중 하나를 동적으로 조회해오는 것이 목표다. 예를 들어, 기상청 api로 날씨를 조회하다 오류가 발생해서 다른 날씨 api로 호출하는 방식이다.
잡설은 그만하고 날씨 open api를 활용하는 단계를 밟아보자.
우선 유명한 날씨 open api는 세가지다. 세가지 모두 무료로 api를 제공한다.
결정 시에 고려해야 할 점은 api를 call할 수 있는 횟수, 금액, 제공하는 api의 종류다.
먼저 결과를 말하자면 3번을 뒤늦게 알게 된 관계로, 나는 1번과 2번을 사용했다. (아큐웨더 누구 코에 붙이는 call 수인지 모르겠음)
이제 각각의 홈페이지에 들어가, api key를 발급 받는다. 해당 과정은 어렵지 않기 때문에 생략하겠다.
예보 api를 결정해야 하는 이유는 사이트마다 여러개의 예보 api를 제공하기 때문이다. 아래는 무료 기준으로 사용할 수 있는 예보 api다.
나는 우선 기상청의 초단기실황조회 api와 아큐웨더의 1시간당 예보를 선택하였다. 왜냐하면 뛰는 사람 입장에선 지금의 날씨가 필요하다고 느꼈기 때문이다. 만약 앞으로의 날씨 현황도 알아야 한다면 기상청의 단기예보조회와 아큐웨더의 5일 예보를 선택하지 않을까 싶다.
우선 외부와 통신하는 케이스는 요청, 응답의 명세 정리가 필수다. 그래야만 내 프로젝트의 맥락에 맞게 응답 데이터를 변환할 수 있기 때문이다. 또한 나는 하나의 요청을 통해 동적으로 호출할 open api를 결정할 생각이었고, 이때 다형성을 활용하려면 추상화가 필수이기 때문에 명세화를 잘 해두어야만 했다.
여담인데, 전직장에서 개발한 프로그램의 90%가 외부 채널과 통신 해야하는 케이스였던 덕분에 좋은 습관을 들일 수 있었던 것 같다.
요청 url : http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst
항목명(영문) | 항목명(국문) | 항목크기 | 항목구분 | 샘플데이터 | 항목설명 |
---|---|---|---|---|---|
serviceKey | 인증키 | 100 | 1 | 인증키(URL Encode) | 공공데이터포털에서 발급받은 인증키 |
numOfRows | 한 페이지 결과 수 | 4 | 1 | 50 | 한 페이지 결과 수 Default: 10 |
pageNo | 페이지 번호 | 4 | 1 | 1 | 페이지 번호Default: 1 |
dataType | 응답자료형식 | 4 | 0 | XML | 요청자료형식(XML/JSON)Default: XML |
base_date | 발표일자 | 8 | 1 | 20210628 | ‘21년 6월 28일발표 |
base_time | 발표시각 | 4 | 1 | 0500 | 05시 발표* 하단 참고자료 참조 |
nx | 예보지점 X 좌표 | 2 | 1 | 55 | 예보지점의 X 좌표값*별첨 엑셀 자료 참조 |
ny | 예보지점 Y 좌표 | 2 | 1 | 127 | 예보지점의 Y 좌표값*별첨 엑셀 자료 참조 |
항목명(영문) | 항목명(국문) | 항목크기 | 항목구분 | 샘플데이터 | 항목설명 |
---|---|---|---|---|---|
numOfRows | 한 페이지 결과 수 | 4 | 1 | 50 | 한 페이지당 표출데이터 수 |
pageNo | 페이지 번호 | 4 | 1 | 1 | 페이지 수 |
totalCount | 데이터 총 개수 | 10 | 1 | 1 | 데이터 총 개수 |
resultCode | 응답메시지 코드 | 2 | 1 | 00 | 응답 메시지코드 |
resultMsg | 응답메시지 내용 | 100 | 1 | NORMAL SERVICE | 응답 메시지 설명 |
dataType | 데이터 타입 | 4 | 1 | XML | 응답자료형식 (XML/JSON) |
baseDate | 발표일자 | 8 | 1 | 20210628 | ‘21년 6월 28일 발표 |
baseTime | 발표시각 | 6 | 1 | 0500 | 05시 발표 |
fcstDate | 예보일자 | 8 | 1 | 20210628 | ‘21년 6월 28일 예보 |
fcstTime | 예보시각 | 4 | 1 | 0600 | 6시 예보 |
category | 자료구분문자 | 3 | 1 | TMP | 자료구분코드 * 하단 코드값 정보 참조 |
fcstValue | 예보 값 | 2 | 1 | 21 | 하단 코드값 정보 참조 |
nx | 예보지점 X 좌표 | 2 | 1 | 55 | 입력한 예보지점 X 좌표 |
ny | 예보지점 Y 좌표 | 2 | 1 | 127 | 입력한 예보지점 Y 좌표 |
예보구분 | 항목값 | 항목명 | 단위 | 압축bit수 |
---|---|---|---|---|
초단기실황 | T1H | 기온 | ℃ | 10 |
RN1 | 1시간 강수량 | mm | 8 | |
UUU | 동서바람성분 | m/s | 12 | |
VVV | 남북바람성분 | m/s | 12 | |
REH | 습도 | % | 8 | |
PTY | 강수형태 | 코드값 | 4 | |
VEC | 풍향 | deg | 10 | |
WSD | 풍속 | m/s | 10 |
에러코드 | 에러메세지 | 설명 |
---|---|---|
00 | NORMAL_SERVICE | 정상 |
01 | APPLICATION_ERROR | 어플리케이션 에러 |
02 | DB_ERROR | 데이터베이스 에러 |
03 | NODATA_ERROR | 데이터없음 에러 |
04 | HTTP_ERROR | HTTP 에러 |
05 | SERVICETIME_OUT | 서비스 연결실패 에러 |
10 | INVALID_REQUEST_PARAMETER_ERROR | 잘못된 요청 파라메터 에러 |
11 | NO_MANDATORY_REQUEST_PARAMETERS_ERROR | 필수요청 파라메터가 없음 |
12 | NO_OPENAPI_SERVICE_ERROR | 해당 오픈API서비스가 없거나 폐기됨 |
20 | SERVICE_ACCESS_DENIED_ERROR | 서비스 접근거부 |
21 | TEMPORARILY_DISABLE_THE_SERVICEKEY_ERROR | 일시적으로 사용할 수 없는 서비스 키 |
22 | LIMITED_NUMBER_OF_SERVICE_REQUESTS_EXCEEDS_ERROR | 서비스 요청제한횟수 초과에러 |
30 | SERVICE_KEY_IS_NOT_REGISTERED_ERROR | 등록되지 않은 서비스키 |
31 | DEADLINE_HAS_EXPIRED_ERROR | 기한만료된 서비스키 |
32 | UNREGISTERED_IP_ERROR | 등록되지 않은 IP |
33 | UNSIGNED_CALL_ERROR | 서명되지 않은 호출 |
99 | UNKNOWN_ERROR | 기타에러 |
{
"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도 호출하라는건 사실상 별로 못한다고 보면 된다. (그냥 아큐웨더말고 오픈웨더 쓰는 거 추천)
Name | Description |
---|---|
locationKey | location key provided by accu weather |
apikey | Provided API Key. |
language | String indicating the language in which to return the resource |
details | Boolean value specifies whether or not to include full details in the response. |
metric | Boolean value specifies whether or not to display metric values. |
Parameter | Type | Description |
---|---|---|
DateTime | string | DateTime of the forecast, displayed in ISO8601 format. |
Temperature.Value | double | Rounded value in specified units. May be NULL. |
RelativeHumidity | int32 | Relative humidity. May be NULL. |
Rain.Value | double | Rounded value in specified units. May be NULL. |
Snow.Value | double | Rounded value in specified units. May be NULL. |
HTTP Code | Description |
---|---|
400 | Request had bad syntax or the parameters supplied were invalid |
401 | Unauthorized. API authorization failed |
403 | Unauthorized. You do not have permission to access this endpoint |
404 | Server has not found a route matching the given URI |
500 | Server encountered an unexpected condition which prevented it from fulfilling the request |
[
{
"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를 설정하는 것은 이미 충분히 작성된 글들이 많으므로 생략하고 아래 목록을 기록할 예정이다.