モノトーンの伝説日記

Apex Legends, Splatoon, Programming, and so on...

HttpParameterKit とかいうよくわからないもの作った。

 どこに需要があるのか全くわからない。

github.com

1. 勝手にいい感じに条件で分けて、勝手にいい感じにデフォルト値のフィルターしてくれる子

 まあ、割とコンセプトとしては条件分岐がめんどくさかったから、と言う感じ。公式 Repo のソースにはないけど、以下のような感じを想定した。

 MastodonAPI でいい感じにするっていう。

timelines - Mastodon documentation

func compareVersion(_ target: String, greaterThanOrEqualTo value: String) -> Bool {
  value.compare(target, options: .numeric) != .orderedDescending
}

@HttpParameterBuilder
func getParameterDefines(version: String) -> [HttpParameter] {
  HPBool("local", default: false)
  if compareVersion(version, greaterThanOrEqualTo: "3.1.4") {
    HPBool("remote", default: false)
  }
  if compareVersion(version, greaterThanOrEqualTo: "2.3.0") {
    HPBool("only_media", default: false)
  }
  HPInt("limit", default: 20, in: 1...40)
  HPString("test", default: "日本語<も>\t含めてみます。", suppressDefault: false)
  HPPattern {
    HPSet {
      HPString("since_id")
    } optionals: {
      HPString("max_id")
    }

    if compareVersion(version, greaterThanOrEqualTo: "3.3.0") {
      HPSet {
        HPString("min_id")
      } optionals: {
        HPString("max_id")
      }
    } else if compareVersion(version, greaterThanOrEqualTo: "2.6.0") {
      HPSet {
        HPString("min_id")
      }
    }
        
    HPSet {
      HPString("max_id")
    }
  }
}

let def220 = getParameterDefines(version: "2.2.0")
let def300 = getParameterDefines(version: "3.0.0")
let def330 = getParameterDefines(version: "3.3.0")
let params: [String: AnyHashable] = [
  "local": true,
  "only_media": true,
  "limit": 40,
  "since_id": "1234",
  "max_id": "3456",
  "min_id": "3456",
]

do {
  let q = try def300.query(params)
  let x = try def300.xml(params, root: "params")
  let j = try def300.json(params)
  let n = try def300.msgpack(params)
} catch {
  print(error.localizedDescription)
}

 なぜか知らないけど、Query だけ必要だけど、気がついたら、XMLJSON も MessagePack も実装してた。まあ気が向いたら、BSON とか CBOR、BinaryMesasge とか手当たり次第対応するかも。

 まあその前に、HPArray で Array 構造ブチ込めるようにすべきなんだろうけど、まだ未対応です。

2. 3 日ぐらいで書いた

 元々の構想自体はあって、事前検証を組んで、あとはパラメーターをくみ出すっていう流れだったんですけど、途中で

.o0(モノトーンよ、SwiftUI でも使っている resultBuilder 使ってみないか)

※ Swift 5.4? あたりで _functionBuilder から resultBuilder に名前変わったっぽいです。

っていう声が聞こえてきたんですよ。まあそれからずっと本題からそれで書いてました。最初は playground ベースで書いてたんですけど、いい感じにまとまってきたので、Swift Package 化しておきました。

3. 色々と危うい実装

 本当は、HPPattern の場合、不必要な変数がある場合、例外とか投げれればよかったんですが、設計的にだるかったので、何も応答なしで、ただ単に出力として吐き出さない形になってます。個人的にこれ以上、このプロジェクトに時間を取られたくなかったので、公開するにあたって必死にテスト書いてましたw

 あとは、本当は内部構造的に共通化できる部分があるので、綺麗に書きたかったんですが、まあ上でも述べた通り時間取られたくなかったので、割と共通化できるのにしてないところあります。

 内部には、Query のエンコードXMLString エンコードJSONString エンコード、そして MessagePack のエンコードが実装されていますが、一応 spec 参照しましたが、テスト書いてないので、ちゃんと動くか知りません。まあ手元では動いてるので、大丈夫って感じで通してます。

 と言うことで、言い訳を並べてみましたが、PR 大歓迎です。ポータブルで取り回しやすさを意識して書いた割には結構デカくなってしまいました。デコードはまあ、Codable ですると思うので、ないです。一応 Codable に対応してる、フォーマット類のリンク貼っておきますね。

 XML

github.com

 YAML

github.com

 MessagePack

github.com

 CBOR

github.com

最後に

 作ったのはいいけど、やっぱり捨てるかもしれないレベルのプロダクトです。

 もっといい感じの書き方ありますかねぇ? なんかデータ構造で上手く条件も表現しつつ、かつコンパイル時検証可能みたいな感じのコードがパッと思いつかなくて、もっといい方法があると思うんですけどね。

 そんな疑問を思いながらコードを書き続けてたらできたものでした。