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 OpenAPIpathswithOperationObject. - Parameter Inference: Generates path, query, header, and cookie parameters, including required flags and examples.
- Request & Response Bodies: Maps
RequestBodyandResponsesoptions 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 and 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|cookieparameters.
Schema Generation
Nova inspects Go types via reflection to build JSON Schemas:
- Structs:
- Generates
components.schemasentries. - Honors
json:"...",description:"...",example:"..."tags. - Marks fields non‐nullable or required unless
omitempty. - 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 and 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.htmllink (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)
}
}