From 770689d0283a36827ba1242ac479415d02255632 Mon Sep 17 00:00:00 2001 From: jinsu Date: Wed, 3 Dec 2025 20:10:38 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B8=B0=EC=83=81=EC=B2=AD=20API=20=ED=97=88?= =?UTF-8?q?=EB=B8=8C=EB=A5=BC=20=EA=B8=B0=EB=B0=98=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 74 +++++++++++++++++++++++++++++++++++++++ api/main.tsp | 98 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 142 insertions(+), 30 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..6c0d487 --- /dev/null +++ b/README.md @@ -0,0 +1,74 @@ +# 날짜 정보 수집처 + +## 기상청 API 허브 + +- + +### API + +많은 API가 제공되나, 기상 예보를 위해서는 2개만 보면 된다. + +#### 초단기 예보 + + + +- 제공하는 범위가 짧다. 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) | + +#### 단기 예보 + + + +- 제공하는 범위가 대충 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)는 (위도, 경도)가 아니다. +> 홈페이지에서 동네예보 지점 좌표(위경도) 참고자료를 다운로드 받아 확인할 수 있다. + +### 평가 + +다소 구식 인터페이스이지만, 한국에서 사실상 유일한 공공 기상 데이터 출처이므로 필수적으로 활용해야 한다. diff --git a/api/main.tsp b/api/main.tsp index 642424e..4519a27 100644 --- a/api/main.tsp +++ b/api/main.tsp @@ -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 | 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; + }; }