HTTP Runtime

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

LayerPackageRole
Router contractgithub.com/go-sphere/httpxEngine, Router, Handler, Middleware, Context
Adaptershttpx/ginx, httpx/fiberx, httpx/echox, httpx/hertzxWrap a concrete framework
Envelopesgithub.com/go-sphere/sphere/server/httpzWithJson, DataResponse, ErrorResponse
Middlewaresphere/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.
  • code is an application code. It is 0 unless the error implements httpx.CodeError.
  • message is user-facing. It is the generic status text unless the error implements httpx.MessageError with a non-empty message.
  • error (err.Error()) is included only when httpz.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.Engine

Replace ginx with fiberx, echox, or hertzx without changing generated service interfaces. Keep:

  • generated Register*HTTPServer(route httpx.Router, srv ...)
  • binding tags from sphere.binding
  • httpz envelopes, 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).

Related

Last updated on