OpenAPI
Nova’s OpenAPI support automatically generates and serves an OpenAPI 3.0 specification for your routes, plus an embedded Swagger UI. It provides:
- Automatic Spec Generation: Reflects Go structs, route definitions, parameters, request bodies, and responses into a valid OpenAPI 3.0 document.
- Component Schemas: Deduplicates and reuses schema definitions for structs, arrays, maps, and basic types.
- Path & Operation Mapping: Converts your router’s methods (
Get
,Post
, etc.) into OpenAPIpaths
withOperationObject
s. - Parameter Inference: Generates path, query, header, and cookie parameters, including required flags and examples.
- Request & Response Bodies: Maps
RequestBody
andResponses
options to JSON media types and schemas. - Servers Configuration: Embeds one or more server definitions (URLs) into the spec.
- Spec Endpoint: Serves the JSON spec at a configurable path (e.g.
/openapi.json
). - Swagger UI: Embeds Swagger UI assets under a prefix (e.g.
/docs
), complete with static asset handling.
Table of Contents
Getting Started
To enable OpenAPI support in your Nova-powered app:
-
Import Nova’s router and OpenAPI helpers:
import "github.com/xlc-dev/nova/nova"
-
Define your routes with
RouteOptions
(including tags, summary, parameters, request/response schemas). -
Call:
router.ServeOpenAPISpec("/openapi.json", nova.OpenAPIConfig{ Title: "My Nova API", Version: "1.0.0", Description: "This is a sample API built with Nova.", Servers: []nova.Server{{URL: fmt.Sprintf("http://%s:%d", host, port)}}, }) router.ServeSwaggerUI("/docs")
-
Start your server as usual:
nova.Serve(ctx, router)
.
Core Concepts
OpenAPIConfig
Holds top‐level metadata for the spec:
type OpenAPIConfig struct {
Title string // API title (required)
Version string // Spec version (required)
Description string // Optional description
Servers []Server // List of servers (URL + optional description)
}
RouteOptions & ResponseOption
Attach OpenAPI metadata when registering routes:
type RouteOptions struct {
Tags []string // Operation tags (grouping)
Summary string // Short summary
Description string // Detailed description
OperationID string // Unique operation ID
Deprecated bool // Mark as deprecated
RequestBody interface{} // Request schema
Responses map[int]ResponseOption
Parameters []ParameterOption
}
type ResponseOption struct {
Description string // Response description
Body interface{} // Schema
}
- Responses: map HTTP status codes to
ResponseOption
. - Parameters: define additional
in:path|query|header|cookie
parameters.
Schema Generation
Nova inspects Go types via reflection to build JSON Schemas:
-
Structs:
- Generates
components.schemas
entries. - Honors
json:"..."
,description:"..."
,example:"..."
tags. - Marks fields non‐nullable or required unless
omitempty
.
- Generates
-
Primitives: maps Go kinds to
type
/format
(e.g.,time.Time
→string
+date‐time
). -
Arrays & Slices:
type: array
+items
. -
Maps:
type: object
+additionalProperties
. -
References: reuses named schemas when the same struct type appears multiple times.
Registering & Serving the Spec
// After defining routes on your `router`:
router.ServeOpenAPISpec("/openapi.json", nova.OpenAPIConfig{
Title: "My API",
Version: "2.0.0",
Description: "Auto‐generated OpenAPI spec",
Servers: []nova.Server{
{URL: "https://api.example.com"},
},
})
- Endpoint: performs a
GET /openapi.json
, returning JSON withContent-Type: application/json
. - Internal: calls
GenerateOpenAPISpec(router, config)
under the hood.
Serving Swagger UI
Nova embeds the official Swagger UI and serves it statically:
router.ServeSwaggerUI("/docs")
-
Access:
GET /docs
→ redirects to/docs/
and servesindex.html
.GET /docs/{file}
→ serves CSS, JS, and favicon from embedded assets.
-
Customization: To point the UI at your spec URL, pass query parameters to the
/docs/index.html
link (e.g.?url=/openapi.json
).
Full Example
package main
import (
"fmt"
"log"
"net/http"
"os"
"strconv"
"time"
"github.com/xlc-dev/nova/nova"
)
func main() {
cli, err := nova.NewCLI(&nova.CLI{
Name: "item-api",
Version: "1.0.0",
Description: "A simple item API with OpenAPI & Swagger UI",
GlobalFlags: []nova.Flag{},
Action: func(ctx *nova.Context) error {
router := nova.NewRouter()
type Item struct {
ID int `json:"id" description:"Item ID"`
Name string `json:"name" example:"Widget"`
CreatedAt time.Time `json:"createdAt" description:"Creation timestamp"`
}
router.Get("/items/{id}", func(w http.ResponseWriter, r *http.Request) {
idStr := router.URLParam(r, "id")
id, _ := strconv.Atoi(idStr)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w,
`{"id":%d,"name":"Item%d","createdAt":"%q"}`,
id, id, time.Now().Format(time.RFC3339),
)
}, &nova.RouteOptions{
Tags: []string{"Items"},
Summary: "Retrieve an item by ID",
Parameters: []nova.ParameterOption{{
Name: "id",
In: "path",
Description: "ID of the item to retrieve",
Schema: int(0),
}},
Responses: map[int]nova.ResponseOption{
200: {Description: "Success", Body: &Item{}},
404: {Description: "Not found"},
},
})
router.ServeOpenAPISpec("/openapi.json", nova.OpenAPIConfig{
Title: "Item API",
Version: "1.0.0",
Description: "API for managing items",
Servers: []nova.Server{
{URL: fmt.Sprintf("http://%s:%d", "localhost", 8080)},
},
})
router.ServeSwaggerUI("/docs")
return nova.Serve(ctx, router)
},
})
if err != nil {
log.Fatalf("failed to initialize CLI: %v", err)
}
if err := cli.Run(os.Args); err != nil {
log.Fatalf("runtime error: %v", err)
}
}