Primitive-based types are not reused in the generated OAS.
Hey there!
I've got the following types
var _ huma.SchemaTransformer = CustomHeader("")
type CustomHeader string
func (h CustomHeader) TransformSchema(r huma.Registry, s *huma.Schema) *huma.Schema {
s.Type = "string"
s.Description = "Custom header Description. The CustomHeader schema should be reused across all endpoints that use it."
return s
}
type CreateUser struct {
Body struct {
Name string `json:"name" doc:"The name."`
}
CustomHeader CustomHeader `header:"X-Custom-Header"`
}
type UpdateUser struct {
Body struct {
Name string `json:"name" doc:"The name."`
}
CustomHeader CustomHeader `header:"X-Custom-Header"`
}
type Output struct {
Body struct {
Message string `json:"message" doc:"The message."`
}
}
With the following routes
huma.Post(api, "/user", func(ctx context.Context, req *CreateUser) (*Output, error) {
resp := &Output{}
resp.Body.Message = "It works!"
return resp, nil
})
huma.Patch(api, "/user/{id}", func(ctx context.Context, req *UpdateUser) (*Output, error) {
resp := &Output{}
resp.Body.Message = "It works!"
return resp, nil
}}
I expect that CustomHeader would be re-used via $ref in the generated OAS.
Instead the CustomHeader schema is embedded into all the endpoints
paths:
/user:
post:
operationId: post-user
parameters:
- description: Custom header Description. The CustomHeader schema should be reused across all endpoints that use it.
in: header
name: X-Custom-Header
schema:
description: Custom header Description. The CustomHeader schema should be reused across all endpoints that use it.
type: string
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUserBody"
required: true
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/OutputBody"
description: OK
default:
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ErrorModel"
description: Error
summary: Post user
/user/{id}:
patch:
operationId: patch-user-by-id
parameters:
- description: Custom header Description. The CustomHeader schema should be reused across all endpoints that use it.
in: header
name: X-Custom-Header
schema:
description: Custom header Description. The CustomHeader schema should be reused across all endpoints that use it.
type: string
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateUserBody"
required: true
responses:
"200":
content:
application/json:
schema:
$ref: "#/components/schemas/OutputBody"
description: OK
default:
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ErrorModel"
description: Error
summary: Patch user by ID
Can an operation be registered to force Huma to reuse shared schemas?
Thank you.
I also tried to reuse this schema via registry, but no luck
router := chi.NewMux()
cfg := huma.DefaultConfig("My API", "1.0.0")
api := humachi.New(router, cfg)
customHeaderSchema := cfg.Components.Schemas.Schema(reflect.TypeOf(CustomHeader("")), true, "")
huma.Register(api, huma.Operation{
OperationID: "UserCreate",
Method: http.MethodPost,
Path: "/users",
Parameters: []*huma.Param{
{
// Omitting the header fields.
Ref: customHeaderSchema.Ref,
},
},
Tags: []string{"users"},
}, func(ctx context.Context, req *CreateUser) (*Output, error) {
resp := &Output{}
resp.Body.Message = "It works!"
return resp, nil
})
huma.Register(api, huma.Operation{
OperationID: "UserUpdate",
Method: http.MethodPatch,
Path: "/users/{id}",
Parameters: []*huma.Param{
{
// Omitting the header fields.
Ref: customHeaderSchema.Ref,
},
},
Tags: []string{"users"},
}, func(ctx context.Context, req *UpdateUser) (*Output, error) {
resp := &Output{}
resp.Body.Message = "It works!"
return resp, nil
})
@superstas you are correct that this is currently not supported. All primitive types will be defined inline in the schema, which is done to keep from having every type get its own $ref. In the future we may want to let you opt-in to using a ref, but there's no code for that at the moment. I'm open to ideas & a PR on this if the feature is important to you.
@danielgtaylor, thank you for the clarification.
Yes, it is important to us to simplify our specs as much as possible by using $ref.
I'll look deeper at the codebase and the possibilities of extending this logic.