GoとTypeScriptで Structured Field Values のパーサーを書きました。
- github.com/shogo82148/go-sfv: Go版実装
- github.com/shogo82148/sfvjs: TypeScript版実装
背景
そもそも Structured Field Values (SFV) とはなにか、なぜ登場したのか、という背景はこちらの記事をどうぞ。
HTTP APIを開発していると、アプリケーション独自のHTTPフィールドを定義することがあります。 そういうときに、標準にしたがっておいたほうが何かと楽だろう、ということでSFVを採用しました。
しかしいい感じのSFVのパーサーがなかなか見つからなかったので、自作することにした、というわけです。
Go実装
Go のモジュールとして公開されているので、いつものように go get
してきましょう。
go get github.com/shogo82148/go-sfv
GoでSFVをパースする
DecodeItem、DecodeList、 DecodeDictionary を使います。
net/http.Header.Valuesの戻り値を直接受け取れるよう、
各関数は []string
を受け取るようにしました。
package main
import (
"fmt"
"net/http"
"github.com/shogo82148/go-sfv"
)
func main() {
h := make(http.Header)
h.Add("Example", `2; foourl="https://foo.example.com/"`)
item, err := sfv.DecodeItem(h.Values("Example"))
if err != nil {
panic(err)
}
fmt.Println(item.Value)
fmt.Println(item.Parameters.Get("foourl"))
// Output:
// 2
// https://foo.example.com/
}
item.Value
は interface{}
型で返ってくるので、必要に応じて型アサーションを行います。
switch val := item.Value.(type) {
case int64: // Integers
case float64: // Decimals
case string: // Strings
case sfv.Token: // Tokens
case bool: // Booleans
case time.Time: // Dates
case sfv.DisplayString: // Display Strings
}
GoでSFVをエンコードする
EncodeItem、EncodeList、 EncodeDictionaryを使用します。
package main
import (
"fmt"
"github.com/shogo82148/go-sfv"
)
func main() {
item := sfv.Item{
Value: 2,
Parameters: sfv.Parameters{
{
Key: "foourl",
Value: "https://foo.example.com/",
},
},
}
fmt.Println(sfv.EncodeItem(item))
// Output:
// 2;foourl="https://foo.example.com/" <nil>
}
TypeScript実装
NodeとDenoに対応しています。
npmからインストールする場合は、
npm install --save @shogo82148/sfv
jsrからインストールする場合は、
deno add @shogo82148/sfv
です。
TypeScriptでSFVをパースする
decodeItem、decodeList、 decodeDictionary を使います。
import { decodeItem } from "@shogo82148/sfv";
const item = decodeItem('2; foourl="https://foo.example.com/"')
console.log(item.value); // Integer { value: 2 }
console.log(item.parameters.get("foourl")); // https://foo.example.com/
instanceof
や typeof
を使って型を判断します。
const value = item.value;
if (value instanceof Integer) {
// Integers
}
if (value instanceof Decimal) {
// Decimals
}
if (typeof value === "string") {
// Strings
}
if (value instanceof Token) {
// Tokens
}
if (value instanceof Uint8Array) {
// Binary Sequences
}
if (typeof value === "boolean") {
// Booleans
}
if (value instanceof Date) {
// Dates
}
if (value instanceof DisplayString) {
// Display Strings
}
TypeScriptでSFVをエンコードする
encodeItem、encodeList、 encodeDictionary を使用します。
import { encodeItem, Integer, Item, Parameters } from "@shogo82148/sfv";
const item = new Item(
new Integer(2),
new Parameters([["foourl", "https://foo.example.com/"]])
);
console.log(encodeItem(item)); // 2;foourl="https://foo.example.com/"
Integer と Decimal について
TypeScript版で特徴的なのは Integer
型と Decimal
型の存在です。
TypeScript自体には「整数」を表す型はなく、すべて number
型で表されます。
でもそこはしっかり区別して欲しい、ということで Integer
型と Decimal
型を独自に定義しました。
Integer
型と Decimal
型は valueOf
メソッドで元の値を取り出せます。
Decimal
型は引数にたとえ整数が渡されたとしても、小数としてシリアライズします。
const i = new Integer(42);
console.log(i.valueOf()); // 42
console.log(encodeItem(new Item(i))); // 42
const d = new Decimal(42);
console.log(d.valueOf()); // 42
console.log(encodeItem(new Item(d))); // 42.0
まとめ
GoとTypeScriptで Structured Field Values のパーサーを書きました。
- github.com/shogo82148/go-sfv: Go版実装
- github.com/shogo82148/sfvjs: TypeScript版実装
ぜひ利用してみてください。フィードバックをお待ちしてます。
うさぎの耳はぴょんと立ち、
新しいSFVに心は躍る。
コードの中で踊るデータ、
標準化の夢、実現への道。
みんなで集まり、喜びを分かち合う、
うさぎたちの楽しい冒険が始まる! 🐰✨by CodeRabbit