mcpField
C
connector-weatherapi

connector-weatherapi

github.com/caffeinelabs開発27.8k 回インストール1 週間前に更新
リポジトリ

connector-weatherapi について

OpenAPI仕様から生成されたWeatherAPI.com向けMotokoバインディングです。現在、予報、過去、海洋などの天気データを必要とするアプリケーション向けに、読み取り専用のGET操作を9種類提供します。

主な機能

  1. 01WeatherAPI.comのGET操作9種類
  2. 02現在の天気と予報データ
  3. 03過去・未来の天気エンドポイント
  4. 04海洋・天文データ
  5. 05タイムゾーン、IP検索、自動補完

活用シーン

  1. 01canisterで現在の天気を取得
  2. 02予報や過去の天気データを取得
  3. 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.jsonRealtimeWeather200Response
forecastWeather(cfg, q, days, dt, unixdt, hour, lang, alerts, aqi, tp)/forecast.jsonForecastWeather200Response
historyWeather(cfg, q, dt, unixdt, endDt, unixendDt, hour, lang)/history.jsonFutureWeather200Response
futureWeather(cfg, q, dt, lang)/future.jsonFutureWeather200Response
marineWeather(cfg, q, days, dt, unixdt, hour, lang)/marine.jsonMarineWeather200Response
astronomy(cfg, q, dt)/astronomy.jsonAstronomy200Response
timeZone(cfg, q)/timezone.jsonLocation
ipLookup(cfg, q)/ip.jsonIp
searchAutocompleteWeather(cfg, q)/search.json[Search]

daysは数値ではなく列挙型です。ForecastWeatherDaysParameterは#_1_~#_14_、MarineWeatherDaysParameterは#_1_~#_7_です(数値の列挙値をジェネレーターがエスケープするためにアンダースコアが使われます。#_3や3ではなく#_3_です)。

APIキーの設定

  1. weatherapi.comでサインアップします。無料プランでは、現在の天気、3日間の予報、天文情報、タイムゾーン、検索、IP検索を利用できます。履歴、将来の天気、海洋情報、14日間予報には有料プランが必要で、無料キーでは403が返されます。
  2. ダッシュボードからキーをコピーし、auth = ?#apiKey keyとして渡します。
  3. クライアントはキーを?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) を表示してください。

コメント