| 4192 | } |
| 4193 | |
| 4194 | func TestWriteResponseTransformErrorStatus(t *testing.T) { |
| 4195 | // This test verifies that if a transformer fails, the client still receives |
| 4196 | // a 500 Internal Server Error status code. |
| 4197 | config := huma.DefaultConfig("Test API", "1.0.0") |
| 4198 | config.Transformers = append(config.Transformers, func(ctx huma.Context, status string, v any) (any, error) { |
| 4199 | return nil, errors.New("transform error") |
| 4200 | }) |
| 4201 | |
| 4202 | mux := http.NewServeMux() |
| 4203 | api := humago.New(mux, config) |
| 4204 | |
| 4205 | huma.Get(api, "/test", func(ctx context.Context, input *struct{}) (*struct { |
| 4206 | Status int |
| 4207 | Body string |
| 4208 | }, error) { |
| 4209 | return &struct { |
| 4210 | Status int |
| 4211 | Body string |
| 4212 | }{Status: http.StatusInternalServerError, Body: "hello"}, nil |
| 4213 | }) |
| 4214 | |
| 4215 | // Use a custom adapter that doesn't call WriteHeader twice if we can. |
| 4216 | // Actually, just let it panic and recover. |
| 4217 | handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 4218 | defer func() { |
| 4219 | if rvr := recover(); rvr != nil { |
| 4220 | // We don't want to call WriteHeader here if it was already called. |
| 4221 | // But we can't easily check if it was called on a raw http.ResponseWriter. |
| 4222 | return |
| 4223 | } |
| 4224 | }() |
| 4225 | mux.ServeHTTP(w, r) |
| 4226 | }) |
| 4227 | |
| 4228 | ts := httptest.NewServer(handler) |
| 4229 | defer ts.Close() |
| 4230 | |
| 4231 | res, err := http.Get(ts.URL + "/test") |
| 4232 | require.NoError(t, err) |
| 4233 | defer res.Body.Close() |
| 4234 | |
| 4235 | body, _ := io.ReadAll(res.Body) |
| 4236 | |
| 4237 | assert.Equal(t, http.StatusInternalServerError, res.StatusCode) |
| 4238 | assert.Contains(t, string(body), "error transforming response") |
| 4239 | } |