기상청 API 허브를 기반으로 작성

This commit is contained in:
2025-12-03 20:10:38 +09:00
parent 58ab7caff3
commit 770689d028
2 changed files with 142 additions and 30 deletions

74
README.md Normal file
View File

@@ -0,0 +1,74 @@
# 날짜 정보 수집처
## 기상청 API 허브
- <https://apihub.kma.go.kr/>
### API
많은 API가 제공되나, 기상 예보를 위해서는 2개만 보면 된다.
#### 초단기 예보
<https://apihub.kma.go.kr/api/typ02/openApi/VilageFcstInfoService_2.0/getUltraSrtFcst>
- 제공하는 범위가 짧다. TODO: 조사 보충 필요
- 00:30 부터 1시간 간격으로 새로운 발표를 한다.
- 00:30, 01:30, ..., 23:30
- 발표 시간으로부터 15분 후에 해당 데이터를 조회할 수 있다.
##### 출력 카테고리 - 초단기
| 코드 | 의미 | 단위 |
| ---- | ------------ | ---------------------------------------------------------------------- |
| T1H | 기온 | ℃ |
| REH | 습도 | % |
| RN1 | 1시간 강수량 | mm |
| SKY | 하늘상태 | 맑음(1), 구름많음(3), 흐림(4) |
| PTY | 강수형태 | 없음(0), 비(1), 비/눈(2), 눈(3), 빗방울(5), 빗방울눈날림(6), 눈날림(7) |
#### 단기 예보
<https://apihub.kma.go.kr/api/typ02/openApi/VilageFcstInfoService_2.0/getVilageFcst>
- 제공하는 범위가 대충 1주일 되는 것 같다. TODO: 조사 보충 필요
- 02:00시부터 3시간 간격으로 새로운 발표를 한다.
- 02:00, 05:00, ..., 23:00
- 발표 시간으로부터 10분 후에 해당 데이터를 조회할 수 있다.
##### 출력 카테고리 - 단기
| 코드 | 의미 | 단위 |
| ---- | ------------ | ------------------------------------------ |
| TMP | 1시간 기온 | ℃ |
| TMN | 일 최저기온 | ℃ |
| TMX | 일 최고기온 | ℃ |
| REH | 습도 | % |
| POP | 강수확률 | % |
| PTY | 강수형태 | 없음(0), 비(1), 비/눈(2), 눈(3), 소나기(4) |
| PCP | 1시간 강수량 | mm |
| SNO | 1시간 신적설 | cm |
| SKY | 하늘상태 | enum: 맑음(1), 구름많음(3), 흐림(4) |
#### 입력 (공통)
- pageNo: 페이지 번호, 1부터 시작
- numOfRows: 한 페이지 결과 수
- 예시: 1000
- dataType: 반환 형식
- enum: XML, JSON
- base_date: 발표 일자, 해당 발표시간껄 보여준다는 건지? 이후라는건지? TODO: 조사 보충 필요
- 예시: 20251203
- base_time: 발표 시간, 해당 발표시간껄 보여준다는 건지? 이후라는건지? TODO: 조사 보충 필요
- 예시: 0630
- API 마다 발표 시간이 정해져 있다.
- nx: 예보지점 X 좌표
- ny: 예보지점 Y 좌표
- authKey: 인증키
> 예보지점 (nx, ny)는 (위도, 경도)가 아니다.
> 홈페이지에서 동네예보 지점 좌표(위경도) 참고자료를 다운로드 받아 확인할 수 있다.
### 평가
다소 구식 인터페이스이지만, 한국에서 사실상 유일한 공공 기상 데이터 출처이므로 필수적으로 활용해야 한다.

View File

@@ -1,44 +1,82 @@
import "@typespec/http";
using Http;
@service(#{ title: "Widget Service" })
namespace DemoService;
@service(#{ title: "Seven Skies Service" })
namespace SevenSkiesService;
model Widget {
id: string;
weight: int32;
color: "red" | "blue";
@doc("섭씨 온도(℃)")
scalar Celsius extends numeric;
enum WeatherCondition {
@doc("맑음") Clear: "CLEAR",
@doc("구름많음") Cloudy: "CLOUDY",
@doc("비") Rain: "RAIN",
@doc("눈") Snow: "SNOW",
@doc("비/눈") RainSnow: "RAIN_SNOW",
}
model WidgetList {
items: Widget[];
model DailyForecast {
@doc("해당 날짜")
date: offsetDateTime;
@doc("하루 동안의 예상 최고 기온(℃)")
high: Celsius;
@doc("하루 동안의 예상 최저 기온(℃)")
low: Celsius;
@doc("하루 전체를 대표하는 날씨 상태")
condition: WeatherCondition;
}
model DailyForecastList {
items: DailyForecast[];
}
model HourlyForecast {
@doc("예상 시간")
time: offsetDateTime;
@doc("1시간 동안의 예상 기온(℃)")
temperature: Celsius;
@doc("1시간 동안의 예상 날씨 상태")
condition: WeatherCondition;
}
model HourlyForecastList {
items: HourlyForecast[];
}
@error
model Error {
code: int32;
message: string;
@doc("에러 코드")
errorCode: int32;
@doc("에러 메시지")
errorMessage: string;
}
model AnalyzeResult {
id: string;
analysis: string;
}
@route("/forecasts")
@tag("Forecasts")
interface Forecasts {
@get
@route("/daily")
listDaily(): {
@statusCode statusCode: 200;
@body body: DailyForecastList;
} | {
@statusCode statusCode: 500;
@body body: Error;
};
@route("/widgets")
@tag("Widgets")
interface Widgets {
/** List widgets */
@get list(): WidgetList | Error;
/** Read widgets */
@get read(@path id: string): Widget | Error;
/** Create a widget */
@post create(@body body: Widget): Widget | Error;
/** Update a widget */
@patch update(@path id: string, @body body: MergePatchUpdate<Widget>): Widget | Error;
/** Delete a widget */
@delete delete(@path id: string): void | Error;
/** Analyze a widget */
@route("{id}/analyze") @post analyze(@path id: string): AnalyzeResult | Error;
@get
@route("/hourly")
listHourly(): {
@statusCode statusCode: 200;
@body body: HourlyForecastList;
} | {
@statusCode statusCode: 500;
@body body: Error;
};
}