danielgtaylor / huma

Huma REST/HTTP API Framework for Golang with OpenAPI 3.1
https://huma.rocks/
MIT License
2.11k stars 151 forks source link

Replace default ErrorModel in docs #231

Closed servernoj closed 9 months ago

servernoj commented 9 months ago

I am using custom error reporting logic by means of overriding the huma.NewError function, and it works as expected. It generates an error response described by the following model

type ErrorResponse struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
}

where Code is the app-specific number that we use on the client side to avoid parsing error text to figure out the kind of problem. This logic was established in pre-Huma times, and I am trying to replicate it with Huma.

The problem is that despite errors being properly reported from our endpoints, the docs still show the default ErrorModel for every error status that I list in the Errors field of my operations.

I believe it is happening because of these lines https://github.com/danielgtaylor/huma/blob/42461d5a01b508b5de841a93b056d0e8617f77d0/huma.go#L648-L654 where an exampled (trivial) error is first created based on the default ErrorModel type and then is reflected to create the default error schema.

If my assumption is correct, can something be done to allow for default ErrorModel customization on the level of huma.API creation from huma.Config. Maybe an extra field or type parameter in huma.Config?

If my assumption is wrong, please advise if and how docs can be adjusted to report our app-specific ErrorModel in place of the default one.

Thank you.

danielgtaylor commented 9 months ago

@servernoj I believe this is working correctly as long as you modify huma.NewError before doing any huma.Register calls on your API. If you modify it after registering operations, then those operations will have already created a schema for the built-in RFC7807 error model. You are definitely looking in the right place in the code, we just want that NewError(0, "") call to return with your custom model. For example, here is your error in the Go playground:

https://go.dev/play/p/tnbMzUPn42H?v=gotip

Running the code I get the custom error response:

Error response http://example.com/greet/name_too_long:
{
  "$schema": "https://example.com/schemas/ErrorResponse.json",
  "code": 123,
  "message": "validation failed\nexpected length \u003c= 10 (path.name: name_too_long)"
}

And the custom error schema in the printed OpenAPI:

    ErrorResponse:
      additionalProperties: false
      properties:
        $schema:
          description: A URL to the JSON Schema for this object.
          format: uri
          readOnly: true
          type: string
        code:
          format: int64
          type: integer
        message:
          type: string
      required:
        - code
        - message
      type: object
servernoj commented 9 months ago

@danielgtaylor yes, you are right, I did have it overridden after registering my operations. Once I switched the order it started to work as expected.

In the meantime, I ended up with a nasty "fix" to be included at the very end after operations and NewError override (had to rename my ErrorResponse into ErrorModel first):

delete(api.OpenAPI().Components.Schemas.Map(), "ErrorDetail")
delete(api.OpenAPI().Components.Schemas.Map(), "ErrorModel")
api.OpenAPI().Components.Schemas.Schema(reflect.TypeOf(ErrorModel{}), true, "ErrorModel")

I am glad I don't need to keep it :)

Thank you.