-
-
Notifications
You must be signed in to change notification settings - Fork 214
Description
The sse-test
endpoint below generates an OpenAPI spec that contains a null
type for each of the three output events.
These null
types cause issues downstream when generating clients with e.g. orval.
Error when working with the generated OpenAPI spec:
TypeError: Cannot read properties of null (reading 'nullable')
There is also a discussion in the official OpenAPI spec repo regarding that issue. Link Apparently there are different versions on how to define a null type. type: 'null'
and just 'null'
. Right now huma generates the type as null
without quotes. According to this migration guide from OpenAPI 3.0 to 3.1, null types should be represented as "type": "null"
I am not sure if the issue needs to be fixed on the client generating side, i.e. they need to deal with null
better. Or that huma should represent null
differently when generating the OpenAPI spec, e.g. "type": "null"
.
Below is the code and the generated OpenAPI spec.
Happy to submit a PR with some guidance!
sse-test endpoint
type DefaultMessage struct {
Message string `json:"message"`
}
type UserCreatedEvent struct {
UserID string `json:"userID"`
}
type MailReceivedEvent struct {
UserID string `json:"userID"`
}
func (app *application) RegisterChatTest(api huma.API) {
sse.Register(api, huma.Operation{
OperationID: "sse",
Method: http.MethodGet,
Path: "/sse-test",
Summary: "Server sent events example",
}, map[string]any{
// Mapping of event type name to Go struct for that event.
"message": DefaultMessage{},
"userCreate": UserCreatedEvent{},
"mailRecieved": MailReceivedEvent{},
}, func(ctx context.Context, input *struct{}, send sse.Sender) {
// Send an event every second for 10 seconds.
for x := 0; x < 10; x++ {
send.Data(MailReceivedEvent{UserID: "abc123"})
time.Sleep(1 * time.Second)
}
})
}
Generated OpenAPI spec
"/sse-test": {
"get": {
"summary": "Server sent events example",
"operationId": "sse",
"responses": {
"200": {
"description": "OK",
"content": {
"text/event-stream": {
"schema": {
"type": "array",
"title": "Server Sent Events",
"description": "Each oneOf object in the array represents one possible Server Sent Events (SSE) message, serialized as UTF-8 text according to the SSE specification.",
"items": {
"oneOf": [
null,
null,
null,
{
"type": "object",
"title": "Event message",
"properties": {
"data": { "$ref": "#/components/schemas/DefaultMessage" },
"event": {
"type": "string",
"description": "The event name.",
"const": "message"
},
"id": { "type": "integer", "description": "The event ID." },
"retry": {
"type": "integer",
"description": "The retry time in milliseconds."
}
},
"required": ["data"]
},
{
"type": "object",
"title": "Event userCreate",
"properties": {
"data": { "$ref": "#/components/schemas/UserCreatedEvent" },
"event": {
"type": "string",
"description": "The event name.",
"const": "userCreate"
},
"id": { "type": "integer", "description": "The event ID." },
"retry": {
"type": "integer",
"description": "The retry time in milliseconds."
}
},
"required": ["data", "event"]
},
{
"type": "object",
"title": "Event mailRecieved",
"properties": {
"data": { "$ref": "#/components/schemas/MailReceivedEvent" },
"event": {
"type": "string",
"description": "The event name.",
"const": "mailRecieved"
},
"id": { "type": "integer", "description": "The event ID." },
"retry": {
"type": "integer",
"description": "The retry time in milliseconds."
}
},
"required": ["data", "event"]
}
]
}
}
}
}
},
"default": {
"description": "Error",
"content": {
"application/problem+json": { "schema": { "$ref": "#/components/schemas/ErrorModel" } }
}
}
}
}
},