From db469e17bc38e9d63b063af9bd5ed83bbf912685 Mon Sep 17 00:00:00 2001 From: theo sorriaux Date: Wed, 22 Oct 2025 09:28:17 +0200 Subject: [PATCH] msg pack support --- README.md | 12 ++++++------ format/format.go | 13 +++++++------ go.mod | 2 ++ go.sum | 4 ++++ router/renderer.go | 11 +++++++---- serializer/deserialize.go | 7 +++++++ serializer/serialize.go | 15 +++++++++++++++ 7 files changed, 48 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 0727ddb..b6a7662 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,12 @@ Built on top of Gin. Restman can be used with any database as long as you implement the builtin repository interface It come with its own GORM based implementation, compatible with Entity/Model separation but also a more straighforward approach. -## Features +## Features Fully working structure to REST automated route generation using GIN, recursion and generics -Out of the box GORM based ORM -Firewall implementation allowing to filter who can access/edit which data -Serialization groups to control which property are allowed to be readed or wrote using the generated route +Out of the box GORM based ORM +Firewall implementation allowing to filter who can access/edit which data +Serialization groups to control which property are allowed to be readed or wrote using the generated route +Multiple output formats: JSON, JSON-LD, XML, CSV, MessagePack ## TODO, Ideas for myself and for random contributors @@ -21,10 +22,9 @@ entity.ID UUID compatiblility InMemory cache with default redis integration Mongo default Repository Fix XML serialialization -fix CSV serialialization +fix CSV serialialization Check current golang json serialization speed check force lowercase for json ? (golang default serializer is like the only thing in the world who does nt force lowercase) -check messagepack Serializer could be refactord Somehow hooks could be nice ?? (meh) The fireWall could have a builtin requireOwnership diff --git a/format/format.go b/format/format.go index 2533f26..d901c5d 100644 --- a/format/format.go +++ b/format/format.go @@ -4,10 +4,11 @@ type Format string // Const of default formats handled by RestMan const ( - Undefined Format = "undefined" - Unknown = "unknown" - JSON = "application/json" - JSONLD = "application/ld+json" - XML = "text/xml" - CSV = "application/csv" + Undefined Format = "undefined" + Unknown = "unknown" + JSON = "application/json" + JSONLD = "application/ld+json" + XML = "text/xml" + CSV = "application/csv" + MESSAGEPACK = "application/msgpack" ) diff --git a/go.mod b/go.mod index 5b2fba0..71a6472 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,8 @@ require ( github.com/onsi/gomega v1.38.2 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/quic-go v0.54.0 // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect diff --git a/go.sum b/go.sum index c4d82b8..0522a39 100644 --- a/go.sum +++ b/go.sum @@ -96,6 +96,10 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= diff --git a/router/renderer.go b/router/renderer.go index 461c6ca..c98c56e 100644 --- a/router/renderer.go +++ b/router/renderer.go @@ -14,10 +14,11 @@ type SerializerRenderer struct { } var ( - jsonContentType = []string{"application/json; charset=utf-8"} - jsonldContentType = []string{"application/ld-json; charset=utf-8"} - xmlContentType = []string{"application/xml; charset=utf-8"} - csvContentType = []string{"text/csv"} + jsonContentType = []string{"application/json; charset=utf-8"} + jsonldContentType = []string{"application/ld-json; charset=utf-8"} + xmlContentType = []string{"application/xml; charset=utf-8"} + csvContentType = []string{"text/csv"} + messagepackContentType = []string{"application/msgpack"} ) // Render @@ -43,6 +44,8 @@ func (r SerializerRenderer) WriteContentType(w http.ResponseWriter) { writeContentType(w, xmlContentType) case format.CSV: writeContentType(w, csvContentType) + case format.MESSAGEPACK: + writeContentType(w, messagepackContentType) } } diff --git a/serializer/deserialize.go b/serializer/deserialize.go index 4596f0e..321809a 100644 --- a/serializer/deserialize.go +++ b/serializer/deserialize.go @@ -10,6 +10,7 @@ import ( "github.com/philiphil/restman/format" "github.com/philiphil/restman/serializer/filter" + "github.com/vmihailenco/msgpack/v5" ) // Deserializer encapsulates the deserialization logic @@ -26,6 +27,8 @@ func (s *Serializer) Deserialize(data string, obj any) error { return s.deserializeXML(data, obj) case format.CSV: return s.deserializeCSV(data, obj) + case format.MESSAGEPACK: + return s.deserializeMessagePack(data, obj) default: return fmt.Errorf("unsupported format: %s", s.Format) } @@ -325,3 +328,7 @@ func setFieldFromString(field reflect.Value, value string) error { } return nil } + +func (s *Serializer) deserializeMessagePack(data string, obj any) error { + return msgpack.Unmarshal([]byte(data), obj) +} diff --git a/serializer/serialize.go b/serializer/serialize.go index a368eae..95f2461 100644 --- a/serializer/serialize.go +++ b/serializer/serialize.go @@ -1,6 +1,7 @@ package serializer import ( + "bytes" "encoding/csv" "encoding/json" "encoding/xml" @@ -10,6 +11,7 @@ import ( "github.com/philiphil/restman/format" "github.com/philiphil/restman/serializer/filter" + "github.com/vmihailenco/msgpack/v5" ) type xmlFilterWrapper struct { @@ -107,6 +109,8 @@ func (s *Serializer) Serialize(obj any, groups ...string) (string, error) { return s.serializeXML(obj, groups...) case format.CSV: return s.serializeCSV(obj, groups...) + case format.MESSAGEPACK: + return s.serializeMessagePack(obj, groups...) default: return "", fmt.Errorf("unsupported format: %s", s.Format) } @@ -229,3 +233,14 @@ func writeCSVToString(rows [][]string) (string, error) { } return sb.String(), nil } + +func (s *Serializer) serializeMessagePack(obj any, groups ...string) (string, error) { + data := filter.FilterByGroups(obj, groups...) + var buf bytes.Buffer + encoder := msgpack.NewEncoder(&buf) + encoder.SetCustomStructTag("json") + if err := encoder.Encode(data); err != nil { + return "", err + } + return buf.String(), nil +}