codec

package
v0.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 2, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package codec provides content-type-aware message marshalers for the HTTP transport, supporting JSON and Protobuf bodies.

Index

Constants

View Source
const (
	ContentTypeJSON  = "application/json"
	ContentTypeProto = "application/x-protobuf"
)

Content types understood by the codec package.

Variables

This section is empty.

Functions

func Bind

func Bind(c *gin.Context, msg proto.Message) error

Bind reads the request body and unmarshals it into a protobuf message using the codec selected by the request Content-Type. Unknown or empty content types fall back to JSON.

req := &pb.HelloRequest{}
if err := codec.Bind(c, req); err != nil { ... }

func BindHTTP

func BindHTTP(c *gin.Context, msg proto.Message, template, body string) error

BindHTTP decodes a protobuf request message from the full HTTP surface in one place: path parameters (from the "{field}" placeholders in template), query parameters, and the request body when body == "*". It is the single binding entry point behind server.Method.httpHandler, replacing the per-method hand-written BindPath/BindQuery/Bind sequences that generated code used to emit.

func BindPath

func BindPath(c *gin.Context, msg proto.Message, template string) error

BindPath populates msg from the path parameters declared by template. A template placeholder "{name}" maps to the request message field "name" (via gin's c.Param("name")). Path values are strings; scalar fields are coerced using the same rules as BindQuery. Unknown placeholders are ignored so a single template may carry multiple parameters.

func BindQuery

func BindQuery(c *gin.Context, msg proto.Message) error

BindQuery populates msg from the URL query parameters. Each query key names a request message field (snake_case or lowerCamelCase); values are coerced to the field's scalar type, enum name, repeated scalar, or a nested message field keyed by dot ("a.b=1"). Unknown query keys are ignored.

func BuildPath

func BuildPath(template string, msg proto.Message) (string, error)

BuildPath substitutes the "{field}" placeholders in template with the string form of the matching scalar fields on msg, returning the concrete URL path. It is the client-side inverse of BindPath: where BindPath decodes a path into the message, BuildPath encodes the message back into the path. An unset field renders as the empty string; an unknown placeholder is left verbatim.

func Render

func Render(c *gin.Context, status int, v any)

Render marshals v using the codec selected by the Accept header and writes it with the matching Content-Type. Unknown or empty Accept falls back to JSON. On a marshal error it aborts with HTTP 500.

codec.Render(c, http.StatusOK, &pb.HelloReply{Message: "hi"})

func RenderError

func RenderError(c *gin.Context, err error)

RenderError normalizes an arbitrary error into an *errorsx.ErrorX and writes it as a JSON envelope carrying its code/reason/message/metadata fields, with the matching HTTP status code. Error responses are always JSON: the gRPC transport carries the same error through GRPCStatus(), so a service returns one error and both protocols render it consistently.

Types

type JSON

type JSON struct{}

JSON is the application/json codec, backed by encoding/json.

This is not the codec a protobuf client wants

For a value that implements proto.Message this codec is wrong in both directions, and wrong *late*: encoding/json and protobuf-JSON disagree about every well-known type. A google.protobuf.Timestamp is an RFC3339 string on the wire and a {Seconds, Nanos} struct in Go, so decoding one fails on the first message that actually carries a date —

json: cannot unmarshal string into Go struct field
  Membership.membership.createdAt of type timestamppb.Timestamp

— while an unset timestamp is `null` and decodes cleanly. A client that works against empty data and breaks on real data is the worst shape a defect has. Duration ("1.5s"), FieldMask, Struct/Value and the wrapper types have the same problem, and marshalling goes the other way: protojson servers do not accept {"seconds":…} for a timestamp.

A client that talks to a protobuf server should use ProtoJSON instead. This codec stays the default for the server's own request binding, where it has been in use across every route and where the contract's request messages carry no well-known types — changing that default would alter the accepted wire format of 284 endpoints to fix a client-side defect. See docs/fix.md.

func (JSON) ContentType

func (JSON) ContentType() string

ContentType returns application/json.

func (JSON) Marshal

func (JSON) Marshal(v any) ([]byte, error)

Marshal encodes v as JSON.

func (JSON) Unmarshal

func (JSON) Unmarshal(data []byte, v any) error

Unmarshal decodes JSON into v.

type Marshaler

type Marshaler interface {
	ContentType() string
	Marshal(v any) ([]byte, error)
	Unmarshal(data []byte, v any) error
}

Marshaler marshals and unmarshals a message body and reports its content type.

func FromAccept

func FromAccept(accept string) Marshaler

FromAccept returns the codec matching an Accept header value, defaulting to JSON when it does not request protobuf.

func FromContentType

func FromContentType(contentType string) Marshaler

FromContentType returns the codec matching a request Content-Type header, defaulting to JSON for unknown or empty types.

type Proto

type Proto struct{}

Proto is the application/x-protobuf codec.

func (Proto) ContentType

func (Proto) ContentType() string

ContentType returns application/x-protobuf.

func (Proto) Marshal

func (Proto) Marshal(v any) ([]byte, error)

Marshal encodes a proto.Message into its wire format.

func (Proto) Unmarshal

func (Proto) Unmarshal(data []byte, v any) error

Unmarshal decodes wire bytes into a proto.Message.

type ProtoJSON

type ProtoJSON struct{}

ProtoJSON is the application/json codec backed by protojson.

It is the codec for talking to a service whose messages are protobuf: the wire format is protobuf-JSON, and this is the decoder that reads it. Use it for any protobuf request or response — see JSON for what goes wrong otherwise.

It reads this platform's responses, which protojson would not write

protojson's parser accepts more than its writer emits, and one of the differences is load-bearing here: the contract types 64-bit integers as JSON numbers (see internal/pkg/rest.Marshal), where protojson writes them as quoted strings. protojson parses both forms, so a client using this codec reads `"price":399` and `"price":"399"` alike.

Unknown fields are rejected, matching protojson's default. That is the right default for a typed client: a field the server sends and the client's IDL does not know is a version skew worth reporting, not something to drop.

func (ProtoJSON) ContentType

func (ProtoJSON) ContentType() string

ContentType returns application/json: this is a JSON encoding of a protobuf message, not the binary format.

func (ProtoJSON) Marshal

func (ProtoJSON) Marshal(v any) ([]byte, error)

Marshal encodes a proto.Message as protobuf-JSON.

func (ProtoJSON) Unmarshal

func (ProtoJSON) Unmarshal(data []byte, v any) error

Unmarshal decodes protobuf-JSON into a proto.Message.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL