// Run from the framework root with: go run ./examples/developerTools package main import ( "context" "errors" "flag" "fmt" "io" "net/http" "net/http/httptest" "os" "strconv" _ "time/tzdata" // This example embeds zones; production builds can use -tags timetzdata. "git.yuntuo.hk/k2safe/go-omni/config" "git.yuntuo.hk/k2safe/go-omni/copyx" mysql "git.yuntuo.hk/k2safe/go-omni/database/mysql" "git.yuntuo.hk/k2safe/go-omni/httpc" "git.yuntuo.hk/k2safe/go-omni/logx" ) type Config struct { Database mysql.Config `json:"database"` Server config.Config `json:"server"` } func Default() Config { c := config.Default() c.Log.Output = "stdout" return Config{Database: mysql.DefaultConfig(), Server: c} } func (c Config) Validate() error { if err := c.Database.Validate(); err != nil { return config.AtField("database", err) } return config.AtField("server", c.Server.Validate()) } type Input struct{ Values []TextValue } type TextValue struct{ Number string } type Result struct{ Values []NumberValue } type NumberValue struct{ Number int } func run(path string) error { cfg, err := config.LoadProject(path, Default()) if err != nil { return err } // Validation only: this example never opens a database. logger, err := logx.New(cfg.Server.Log) if err != nil { return err } defer logger.Close() logger.InfoContext(context.Background(), "instance time zone", "configuredZone", cfg.Server.Log.TimeZone) if err := copyx.Check[Input, Result](); !errors.Is(err, copyx.ErrType) { return fmt.Errorf("expected a type mismatch, got %v", err) } // Explicit Go converter owns the number conversion; no JSON mapping file. options := []copyx.Option{copyx.WithConverter(strconv.Atoi)} if err := copyx.Check[Input, Result](options...); err != nil { return err } var output Result if err := copyx.Copy(&output, Input{Values: []TextValue{{Number: "42"}}}, options...); err != nil { return err } fmt.Printf("type check and copy succeeded: %d\n", output.Values[0].Number) server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/created" { w.WriteHeader(http.StatusCreated) } io.WriteString(w, `{"value":"example"}`) })) defer server.Close() client, err := httpc.New(httpc.Config{DisableLogging: true}) if err != nil { return err } defer client.Close() var reply struct { Value string `json:"value"` } if err := client.JSON(context.Background(), http.MethodGet, server.URL, nil, &reply, httpc.WithSuccessStatuses(http.StatusOK)); err != nil { return err } err = client.JSON(context.Background(), http.MethodGet, server.URL+"/created", nil, &reply, httpc.WithSuccessStatuses(http.StatusOK)) var status *httpc.StatusError if !errors.As(err, &status) || status.StatusCode != http.StatusCreated { return fmt.Errorf("expected status rejection, got %v", err) } fmt.Println("strict JSON: 200 accepted, 201 rejected") return nil } func main() { path := flag.String("config", "examples/developerTools/config.yaml", "selected configuration file") flag.Parse() if err := run(*path); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }