はじめに
表題通り、GoでJsonShcemaを利用します。
実装
~/go/go_json_schema $ tree
.
├── go.mod
├── go.sum
├── schema.go
└── schema_test.go
1 directory, 4 files
schema.go
package main
import (
"encoding/json"
)
// JSONをGoの構造体に変換するための定義
type Person struct {
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Age int `json:"age,omitempty"`
Email string `json:"email,omitempty"`
}
// JSONデータを構造体に変換する関数
func ParsePerson(data []byte) (Person, error) {
var person Person
err := json.Unmarshal(data, &person)
return person, err
}
schema_test.go
package main
import (
"encoding/json"
"fmt"
"strings"
"testing"
"github.com/santhosh-tekuri/jsonschema/v5"
)
// JSON Schemaの定義
var personSchema = []byte(`{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Person",
"type": "object",
"properties": {
"firstName": { "type": "string" },
"lastName": { "type": "string" },
"age": {
"type": "integer",
"minimum": 0
},
"email": {
"type": "string",
"format": "email"
}
},
"required": ["firstName", "lastName"]
}`)
// 有効なJSONデータ
var validPersonData = []byte(`{
"firstName": "太郎",
"lastName": "山田",
"age": 30,
"email": "taro@example.com"
}`)
// 無効なJSONデータ(必須フィールドがない)
var invalidPersonData = []byte(`{
"firstName": "太郎"
}`)
func TestPersonSchema(t *testing.T) {
// スキーマのコンパイル
compiler := jsonschema.NewCompiler()
if err := compiler.AddResource("person.json", strings.NewReader(string(personSchema))); err != nil {
t.Fatalf("スキーマの追加エラー: %v", err)
}
schema, err := compiler.Compile("person.json")
if err != nil {
t.Fatalf("スキーマのコンパイルエラー: %v", err)
}
// テストケース
tests := []struct {
name string
data []byte
isValid bool
}{
{
name: "有効なデータ",
data: validPersonData,
isValid: true,
},
{
name: "無効なデータ(必須フィールドがない)",
data: invalidPersonData,
isValid: false,
},
}
// 各テストケースを実行
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// JSONをインターフェースに変換
var personObj interface{}
if err := json.Unmarshal(tt.data, &personObj); err != nil {
t.Fatalf("JSONのパースエラー: %v", err)
}
// スキーマに対して検証
err := schema.Validate(personObj)
if tt.isValid && err != nil {
t.Errorf("有効なはずのデータが無効と判定: %v", err)
}
if !tt.isValid && err == nil {
t.Errorf("無効なはずのデータが有効と判定")
}
fmt.Println("============== personObj", personObj)
// エラーの内容を表示(デバッグ用)
if err != nil {
fmt.Printf("検証エラー (%s): %v\n", tt.name, err)
}
})
}
}