feat: add dependency shutdown and configurable service endpoints

This commit is contained in:
2026-09-24 18:33:24 +08:00
parent 8a348951eb
commit f0991d3ff2
51 changed files with 1433 additions and 73 deletions

View File

@@ -57,6 +57,9 @@ func (c *Context) writeResult(result response.Result) (err error) {
if err != nil {
return apierrors.Internal(err)
}
if result.PreserveStatus {
payload.Status = result.Status
}
if payload.Status < 200 || payload.Status > 599 {
return apierrors.Internal(fmt.Errorf("response encoder returned invalid status %d", payload.Status))
}
@@ -66,6 +69,41 @@ func (c *Context) writeResult(result response.Result) (err error) {
return c.WriteResponse(payload.Status, payload.Header, payload.Body)
}
// RespondStatus uses the current response format and error catalog, but keeps
// the explicit HTTP status even if a catalog/custom encoder selects another.
// This is useful for protocol endpoints such as health probes. Ordinary
// business handlers should use OK/Created or return their error as usual.
func (c *Context) RespondStatus(status int, data any, err error) error {
if c.Responded() {
return nil
}
if status < 200 || status > 599 || status == 204 || status == 205 || status == 304 {
return apierrors.Internal(fmt.Errorf("response requires a body-bearing HTTP status"))
}
result := response.Result{Status: status, Code: "OK", Message: "success", Data: data,
RequestID: c.RequestID(), PreserveStatus: true}
if err != nil {
failure := c.ResolveError(err)
failure.Status = status
c.failure = failure
result.Code, result.Message, result.BusinessCode = failure.Code, failure.Message, failure.BusinessCode
result.Err, result.Failed = err, true
}
writeErr := c.writeResult(result)
if writeErr != nil && !c.Responded() {
// A broken encoder must not fall through to a business error policy
// that acknowledges failures with HTTP 200. Commit a bodyless failure.
failureStatus := status
if failureStatus < 400 {
failureStatus = http.StatusInternalServerError
}
c.failure = c.ResolveError(writeErr)
c.failure.Status = failureStatus
_ = c.WriteResponse(failureStatus, nil, nil)
}
return writeErr
}
// Bytes, Text and XML are explicit wire responses; they bypass any envelope.
func (c *Context) Bytes(status int, contentType string, body []byte) error {
return c.WriteResponse(status, http.Header{"Content-Type": {contentType}}, body)