connector-weatherapi について
OpenAPI仕様から生成されたWeatherAPI.com向けMotokoバインディングです。現在、予報、過去、海洋などの天気データを必要とするアプリケーション向けに、読み取り専用のGET操作を9種類提供します。
主な機能
- 01WeatherAPI.comのGET操作9種類
- 02現在の天気と予報データ
- 03過去・未来の天気エンドポイント
- 04海洋・天文データ
- 05タイムゾーン、IP検索、自動補完
活用シーン
- 01canisterで現在の天気を取得
- 02予報や過去の天気データを取得
- 03タイムゾーンやIP位置を検索
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ caffeinelabs/ skills --skill connector-weatherapiインストール後、Claude Code で/connector-weatherapiを入力して読み込まれたか確認します。
詳細
weatherapi-clientで天気データを取得
WeatherAPI.com のOpenAPI仕様から生成された、Motokoバインディングです。9つの操作はすべて1つのモジュール**Apis/APIsApi**にあり、すべて読み取り専用のGETです。
バックエンド
現在の気温と3日間の最高気温の時系列データを読み取るキャニスターです。デフォルトでは非レプリケートなので、キーを指定するだけです。
import { realtimeWeather; forecastWeather } "mo:weatherapi-client/Apis/APIsApi";
import { type Config; defaultConfig } "mo:weatherapi-client/Config";
import Array "mo:core/Array"; // in scope so `days.map(…)` dot notation resolves
actor {
// The key is a query-string credential. Hold it in a stable variable set by
// an admin call; never hard-code it in source.
func config(apiKey : Text) : Config = { defaultConfig with auth = ?#apiKey apiKey };
// `q` is any WeatherAPI location query: "Zurich", "47.37,8.55", a postcode,
// an IATA code, or "auto:ip".
public func currentTempC(apiKey : Text, q : Text) : async ?Float {
let res = await* realtimeWeather(config apiKey, q, "");
do ? { res.current!.temp_c! };
};
// Daily maxima for the next three days.
public func maxTempsC(apiKey : Text, q : Text) : async [?Float] {
let res = await* forecastWeather(config apiKey, q, #_3_, "", 0, 0, "", "no", "no", 0);
let ?forecast = res.forecast else return [];
let ?days = forecast.forecastday else return [];
days.map(func(d) = do ? { d.day!.maxtemp_c! });
};
}
9つの操作
| 関数 | エンドポイント | 戻り値 |
|---|---|---|
realtimeWeather(cfg, q, lang) | /current.json | RealtimeWeather200Response |
forecastWeather(cfg, q, days, dt, unixdt, hour, lang, alerts, aqi, tp) | /forecast.json | ForecastWeather200Response |
historyWeather(cfg, q, dt, unixdt, endDt, unixendDt, hour, lang) | /history.json | FutureWeather200Response |
futureWeather(cfg, q, dt, lang) | /future.json | FutureWeather200Response |
marineWeather(cfg, q, days, dt, unixdt, hour, lang) | /marine.json | MarineWeather200Response |
astronomy(cfg, q, dt) | /astronomy.json | Astronomy200Response |
timeZone(cfg, q) | /timezone.json | Location |
ipLookup(cfg, q) | /ip.json | Ip |
searchAutocompleteWeather(cfg, q) | /search.json | [Search] |
daysは数値ではなく列挙型です。ForecastWeatherDaysParameterは#_1_~#_14_、MarineWeatherDaysParameterは#_1_~#_7_です(数値の列挙値をジェネレーターがエスケープするためにアンダースコアが使われます。#_3や3ではなく#_3_です)。
APIキーの設定
- weatherapi.comでサインアップします。無料プランでは、現在の天気、3日間の予報、天文情報、タイムゾーン、検索、IP検索を利用できます。履歴、将来の天気、海洋情報、14日間予報には有料プランが必要で、無料キーでは403が返されます。
- ダッシュボードからキーをコピーし、
auth = ?#apiKey keyとして渡します。 - クライアントはキーを
?key=…として付加します(WeatherAPIはAuthorizationヘッダーを使用しません)。そのため、リクエストURLにキーが含まれます。管理者専用の呼び出しで書き込んだ固定の変数に保存し、生成したURLをログに記録しないでください。
呼び出しはデフォルトで非レプリケートです
このパッケージのdefaultConfigにはis_replicated = ?falseが設定されています。ここでは、これは単なるコスト削減ではなく、正確性の要件です。すべてのレスポンスにはリクエストごとに変わる時刻情報(Location.localtime/localtime_epoch、Current.last_updated/last_updated_epoch)が含まれ、秒単位で更新されます。レプリケートされたアウトコールでは、サブネットのすべてのノードがそれぞれリクエストを発行し、本文がビット単位で完全に一致することが求められます。そのため、ほとんどの呼び出しでこれらのフィールドがコンセンサスを妨げるうえ、サイクルも約13倍消費します。自分で設定する必要はありません。デフォルトのままで問題ありません。
is_replicated = ?trueに変更するのは、変動するフィールドを取り除くtransformと併用する場合に限ってください。
すべてのフィールドはオプショナルです
WeatherAPIではレスポンスのフィールドが必須とされていないため、生成されるモデルはすべてオプショナルです。たとえば、RealtimeWeather200Response.current : ?Current、Current.temp_c : ?Floatなどです。ネストしたswitchの代わりに、do ?ブロックで値をたどります(do ? { res.current!.temp_c! })。また、呼び出し元にとってフィールドが存在しない場合にどう扱うかを決めてください。APIでは、プランに含まれないフィールドが省略されます(たとえば、aqi=yesパラメーターを指定しない場合、air_qualityは返されません)。
空文字列とゼロは「省略」を意味します
WeatherAPIは空のlang=や値がゼロの数値を拒否するため、オプショナルなクエリパラメーターは""または0の場合に省略されます。したがって、lang、dt、alerts、aqiには""を、unixdt、tpには0を渡すことで、「指定なし」を表します。nullのままにできる?Textパラメーターはありません。
注意が必要なのは、hour = 0では午前0時が選択されず、hourフィルター全体が省略されて、その日の時間別配列全体が返されることです。00:00が必要な場合は、返されたhour : ?[ForecastForecastdayInnerHourInner]を自分でフィルタリングしてください。
エラー
2xx 以外のレスポンスとデコード失敗では、Error.reject(…) がスローされます。クライアントは
diagnostics を有効にして生成されるため、メッセージは
HTTP <status> body[<n>B]=<first 100 chars>: <reason> となります。追加のログ出力なしで、401(キーが無効)と
403(エンドポイントがプランの対象外)、400(q を解決できない)を判別するのに十分です。try/catch で捕捉し、
Error.message(err) を表示してください。