encoding(serialization codec system)
Thread-safe serialization codec system supporting multiple formats (JSON, XML, YAML, Protocol Buffers, Form) with automatic registration and content-type handling.
The encoding module provides a thread-safe serialization codec system that supports multiple formats (JSON, XML, YAML, Protocol Buffers, Form) with automatic registration and content-type handling.
Features
- Multiple encoding formats support (JSON, XML, YAML, Protocol Buffers, Form)
- Thread-safe codec interface for concurrent usage
- Automatic codec registration system
- Content-type based codec selection
- Protocol Buffers integration with enhanced JSON support
- Custom marshaler/unmarshaler support
- Extensible codec system for custom formats
Core Codec Interface
1package main
2
3import (
4 "fmt"
5 "log"
6
7 "github.com/crazyfrankie/frx/encoding"
8 _ "github.com/crazyfrankie/frx/encoding/json" // Auto-register JSON codec
9)
10
11type User struct {
12 ID int64 `json:"id"`
13 Name string `json:"name"`
14 Email string `json:"email"`
15}
16
17func main() {
18 user := User{
19 ID: 1,
20 Name: "John Doe",
21 Email: "john@example.com",
22 }
23
24 // Get codec by name
25 codec := encoding.GetCodec("json")
26 if codec == nil {
27 log.Fatal("JSON codec not found")
28 }
29
30 // Marshal data
31 data, err := codec.Marshal(user)
32 if err != nil {
33 log.Fatal(err)
34 }
35
36 fmt.Printf("Marshaled: %s\n", string(data))
37
38 // Unmarshal data
39 var decoded User
40 if err := codec.Unmarshal(data, &decoded); err != nil {
41 log.Fatal(err)
42 }
43
44 fmt.Printf("Unmarshaled: %+v\n", decoded)
45}
JSON Encoding
1package main
2
3import (
4 "fmt"
5 "log"
6
7 "github.com/crazyfrankie/frx/encoding"
8 _ "github.com/crazyfrankie/frx/encoding/json"
9)
10
11type Product struct {
12 ID int64 `json:"id"`
13 Name string `json:"name"`
14 Price float64 `json:"price"`
15 Available bool `json:"available"`
16 Tags []string `json:"tags,omitempty"`
17}
18
19func main() {
20 product := Product{
21 ID: 123,
22 Name: "Laptop",
23 Price: 999.99,
24 Available: true,
25 Tags: []string{"electronics", "computers"},
26 }
27
28 // JSON encoding
29 jsonCodec := encoding.GetCodec("json")
30
31 data, err := jsonCodec.Marshal(product)
32 if err != nil {
33 log.Fatal(err)
34 }
35
36 fmt.Printf("JSON: %s\n", string(data))
37
38 // JSON decoding
39 var decoded Product
40 if err := jsonCodec.Unmarshal(data, &decoded); err != nil {
41 log.Fatal(err)
42 }
43
44 fmt.Printf("Decoded: %+v\n", decoded)
45}
Protocol Buffers Support
1package main
2
3import (
4 "fmt"
5 "log"
6
7 "google.golang.org/protobuf/proto"
8 "github.com/crazyfrankie/frx/encoding"
9 _ "github.com/crazyfrankie/frx/encoding/json"
10)
11
12// Assuming you have a protobuf message
13// message UserProto {
14// int64 id = 1;
15// string name = 2;
16// string email = 3;
17// }
18
19func main() {
20 // Create protobuf message
21 userProto := &UserProto{
22 Id: 1,
23 Name: "John Doe",
24 Email: "john@example.com",
25 }
26
27 // JSON codec automatically handles protobuf messages
28 jsonCodec := encoding.GetCodec("json")
29
30 // Marshal protobuf to JSON
31 data, err := jsonCodec.Marshal(userProto)
32 if err != nil {
33 log.Fatal(err)
34 }
35
36 fmt.Printf("Protobuf as JSON: %s\n", string(data))
37
38 // Unmarshal JSON back to protobuf
39 var decoded UserProto
40 if err := jsonCodec.Unmarshal(data, &decoded); err != nil {
41 log.Fatal(err)
42 }
43
44 fmt.Printf("Decoded protobuf: %+v\n", &decoded)
45}
XML Encoding
1package main
2
3import (
4 "fmt"
5 "log"
6
7 "github.com/crazyfrankie/frx/encoding"
8 _ "github.com/crazyfrankie/frx/encoding/xml"
9)
10
11type Book struct {
12 XMLName xml.Name `xml:"book"`
13 ID int64 `xml:"id,attr"`
14 Title string `xml:"title"`
15 Author string `xml:"author"`
16 ISBN string `xml:"isbn"`
17}
18
19func main() {
20 book := Book{
21 ID: 1,
22 Title: "Go Programming",
23 Author: "John Smith",
24 ISBN: "978-0123456789",
25 }
26
27 // XML encoding
28 xmlCodec := encoding.GetCodec("xml")
29
30 data, err := xmlCodec.Marshal(book)
31 if err != nil {
32 log.Fatal(err)
33 }
34
35 fmt.Printf("XML: %s\n", string(data))
36
37 // XML decoding
38 var decoded Book
39 if err := xmlCodec.Unmarshal(data, &decoded); err != nil {
40 log.Fatal(err)
41 }
42
43 fmt.Printf("Decoded: %+v\n", decoded)
44}
YAML Encoding
1package main
2
3import (
4 "fmt"
5 "log"
6
7 "github.com/crazyfrankie/frx/encoding"
8 _ "github.com/crazyfrankie/frx/encoding/yaml"
9)
10
11type Config struct {
12 Server struct {
13 Host string `yaml:"host"`
14 Port int `yaml:"port"`
15 } `yaml:"server"`
16 Database struct {
17 Host string `yaml:"host"`
18 Port int `yaml:"port"`
19 Username string `yaml:"username"`
20 } `yaml:"database"`
21}
22
23func main() {
24 config := Config{}
25 config.Server.Host = "localhost"
26 config.Server.Port = 8080
27 config.Database.Host = "db.example.com"
28 config.Database.Port = 5432
29 config.Database.Username = "admin"
30
31 // YAML encoding
32 yamlCodec := encoding.GetCodec("yaml")
33
34 data, err := yamlCodec.Marshal(config)
35 if err != nil {
36 log.Fatal(err)
37 }
38
39 fmt.Printf("YAML:\n%s\n", string(data))
40
41 // YAML decoding
42 var decoded Config
43 if err := yamlCodec.Unmarshal(data, &decoded); err != nil {
44 log.Fatal(err)
45 }
46
47 fmt.Printf("Decoded: %+v\n", decoded)
48}
Form Encoding
1package main
2
3import (
4 "fmt"
5 "log"
6
7 "github.com/crazyfrankie/frx/encoding"
8 _ "github.com/crazyfrankie/frx/encoding/form"
9)
10
11type LoginForm struct {
12 Username string `form:"username"`
13 Password string `form:"password"`
14 Remember bool `form:"remember"`
15}
16
17func main() {
18 form := LoginForm{
19 Username: "john_doe",
20 Password: "secret123",
21 Remember: true,
22 }
23
24 // Form encoding
25 formCodec := encoding.GetCodec("form")
26
27 data, err := formCodec.Marshal(form)
28 if err != nil {
29 log.Fatal(err)
30 }
31
32 fmt.Printf("Form data: %s\n", string(data))
33
34 // Form decoding
35 var decoded LoginForm
36 if err := formCodec.Unmarshal(data, &decoded); err != nil {
37 log.Fatal(err)
38 }
39
40 fmt.Printf("Decoded: %+v\n", decoded)
41}
Custom Codec Implementation
1package main
2
3import (
4 "encoding/csv"
5 "bytes"
6 "fmt"
7 "reflect"
8 "strconv"
9
10 "github.com/crazyfrankie/frx/encoding"
11)
12
13// Custom CSV codec
14type csvCodec struct{}
15
16func (c csvCodec) Marshal(v any) ([]byte, error) {
17 // Simple CSV marshaling implementation
18 var buf bytes.Buffer
19 writer := csv.NewWriter(&buf)
20
21 // This is a simplified example
22 // In practice, you'd need more sophisticated reflection
23 rv := reflect.ValueOf(v)
24 if rv.Kind() == reflect.Slice {
25 for i := 0; i < rv.Len(); i++ {
26 item := rv.Index(i)
27 var record []string
28
29 // Convert struct fields to strings
30 for j := 0; j < item.NumField(); j++ {
31 field := item.Field(j)
32 record = append(record, fmt.Sprintf("%v", field.Interface()))
33 }
34
35 writer.Write(record)
36 }
37 }
38
39 writer.Flush()
40 return buf.Bytes(), writer.Error()
41}
42
43func (c csvCodec) Unmarshal(data []byte, v any) error {
44 // CSV unmarshaling implementation
45 reader := csv.NewReader(bytes.NewReader(data))
46 records, err := reader.ReadAll()
47 if err != nil {
48 return err
49 }
50
51 // Simplified unmarshaling logic
52 // In practice, you'd need proper reflection handling
53 fmt.Printf("CSV records: %v\n", records)
54 return nil
55}
56
57func (c csvCodec) Name() string {
58 return "csv"
59}
60
61func main() {
62 // Register custom codec
63 encoding.RegisterCodec(csvCodec{})
64
65 // Use custom codec
66 csvCodec := encoding.GetCodec("csv")
67 if csvCodec != nil {
68 fmt.Println("CSV codec registered successfully")
69 }
70}
Content-Type Based Codec Selection
1package main
2
3import (
4 "fmt"
5 "net/http"
6
7 "github.com/crazyfrankie/frx/encoding"
8 _ "github.com/crazyfrankie/frx/encoding/json"
9 _ "github.com/crazyfrankie/frx/encoding/xml"
10)
11
12func handleRequest(w http.ResponseWriter, r *http.Request) {
13 contentType := r.Header.Get("Content-Type")
14
15 var codecName string
16 switch contentType {
17 case "application/json":
18 codecName = "json"
19 case "application/xml", "text/xml":
20 codecName = "xml"
21 default:
22 codecName = "json" // default
23 }
24
25 codec := encoding.GetCodec(codecName)
26 if codec == nil {
27 http.Error(w, "Unsupported content type", http.StatusBadRequest)
28 return
29 }
30
31 // Use codec for request/response handling
32 fmt.Printf("Using codec: %s\n", codec.Name())
33}