huma
huma copied to clipboard
Date response format is returned as date-time
I have an API which specifies that the response is a date, not a date-time. Since go doesn't have a date type, I'm using time.Time but want it to return a date like 2025-03-11. I have configured my response object like this:
Date time.Time `json:"date" format:"date"`
And the docs recognize that it's a date type:
But the API still returns the full timestamp without errors or warnings that I can see:
> curl localhost:8080/test
{"$schema":"http://localhost:8080/schemas/GreetingOutputBody.json","date":"2025-03-11T12:38:07.655129-07:00"}
Full code (adapted from https://huma.rocks/tutorial/your-first-api/, using huma v2.31.0):
package main
import (
"context"
"net/http"
"time"
"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/adapters/humachi"
"github.com/go-chi/chi/v5"
_ "github.com/danielgtaylor/huma/v2/formats/cbor"
)
type GreetingOutput struct {
Body struct {
Date time.Time `json:"date" format:"date"`
}
}
func main() {
router := chi.NewMux()
api := humachi.New(router, huma.DefaultConfig("My API", "1.0.0"))
huma.Get(api, "/test", func(ctx context.Context, input *struct{}) (*GreetingOutput, error) {
resp := &GreetingOutput{}
resp.Body.Date = time.Now()
return resp, nil
})
err := http.ListenAndServe("127.0.0.1:8080", router)
if err != nil {
panic(err)
}
}
Is this a bug? Or is there something else I need to do to properly format (and/or validate) the response? Thanks!
@pgr0ss thanks for opening an issue for this! It isn't actually a Huma thing, but has to do with how Golang serializes time.Time structs, while the format tag is just informational in the generated OpenAPI. Unfortunately there is no field tag to tell Golang's JSON marshaler what format to use, you just always get ISO8601 output by default. You have two options:
- Create a custom
Datetype which serializes how you want by implementingencoding.TextMarshaler. - Use a
stringand set it in your handler code.
https://go.dev/play/p/_lHajInSNiC
Option 1:
type Date time.Time
func (d Date) MarshalText() ([]byte, error) {
return []byte(time.Time(d).Format("2006-01-02")), nil
}
func (d *Date) TransformSchema(r huma.Registry, s *huma.Schema) *huma.Schema {
s.Format = "date"
return s
}
type DateResponse struct {
Body struct {
Date Date `json:"date"`
}
}
huma.Get(api, "/date1", func(ctx context.Context, input *struct{}) (*DateResponse, error) {
resp := &DateResponse{}
resp.Body.Date = Date(time.Now())
return resp, nil
})
Option 2:
type DateStringResponse struct {
Body struct {
Date string `json:"date" format:"date"`
}
}
huma.Get(api, "/date2", func(ctx context.Context, input *struct{}) (*DateStringResponse, error) {
resp := &DateStringResponse{}
resp.Body.Date = time.Now().Format("2006-01-02")
return resp, nil
})
Hope that helps!