HTTP Runtime
Generated HTTP code talks to httpx, not to Gin, Fiber, Echo, or Hertz directly. server/httpz adds the JSON envelopes and handler wrappers that official templates use.
Layers
| Layer | Package | Role |
|---|---|---|
| Router contract | github.com/go-sphere/httpx | Engine, Router, Handler, Middleware, Context |
| Adapters | httpx/ginx, httpx/fiberx, httpx/echox, httpx/hertzx | Wrap a concrete framework |
| Envelopes | github.com/go-sphere/sphere/server/httpz | WithJson, DataResponse, ErrorResponse |
| Middleware | sphere/server/middleware/* | Auth, CORS, online, rate limiter, selector |
protoc-gen-sphere defaults are httpx.Router / httpx.Context / httpx.Handler and httpz.WithJson. See protoc-gen-sphere.
Success Envelope
{
"success": true,
"data": { }
}httpz.WithJson writes HTTP 200 unless the handler set a status through httpx.ResponseInfo (for example 201).
Error Envelope
{
"success": false,
"code": 1001,
"message": "User not found"
}Rules enforced by httpz.AbortWithJsonError:
- HTTP status comes from
httpx.StatusError(or the parser). Invalid statuses become 500. codeis an application code. It is0unless the error implementshttpx.CodeError.messageis user-facing. It is the generic status text unless the error implementshttpx.MessageErrorwith a non-empty message.error(err.Error()) is included only whenhttpz.SetDebugMode(true).
Typed proto errors generated by protoc-gen-sphere-errors implement those interfaces, so .Join() / returning the enum produces a stable client payload. Plain fmt.Errorf and driver errors do not leak internal text in production.
Binding
Generated handlers bind through httpx.Context:
if err := ctx.BindJSON(&in); err != nil {
return nil, err
}
if err := ctx.BindQuery(&in); err != nil {
return nil, err
}
if err := ctx.BindURI(&in); err != nil {
return nil, err
}GET/HEAD/DELETE/OPTIONS never call BindJSON, even if the proto declared body. Enable fail_on_warn on protoc-gen-sphere if you want that to fail generation instead of warning.
Template Wiring
Official templates construct a Gin engine and wrap it:
engine := gin.New()
app := ginx.New(
ginx.WithEngine(engine),
ginx.WithServerAddr(addr),
)
return app // httpx.EngineReplace ginx with fiberx, echox, or hertzx without changing generated service interfaces. Keep:
- generated
Register*HTTPServer(route httpx.Router, srv ...) - binding tags from
sphere.binding httpzenvelopes, unless you override the generator flags
Custom Error Parser
Templates install a parser that maps protovalidate and Ent errors before falling back to httpx.ParseError:
httpz.SetDefaultErrorParser(func(err error) (int32, int32, string) {
var ve *protovalidate.ValidationError
if errors.As(err, &ve) {
return 0, 400, /* joined violation messages */
}
return httpx.ParseError(err)
})The parser return is (code, status, message). AbortWithJsonError still zeros code and replaces message unless the error implements the corresponding httpx interfaces. For a custom parser message to reach the client, wrap with httpx.NewError (or return a generated proto error).