A lightweight adapter for the Gin web framework that automatically generates OpenAPI 3.x specifications from your routes using oaswrap/spec.
- ⚡ Seamless Integration — Works with your existing Gin routes and handlers
- 📝 Automatic Documentation — Generate OpenAPI specs from route definitions and struct tags
- 🎯 Type Safety — Full Go type safety for OpenAPI configuration
- 🔧 Multiple UI Options — Swagger UI, Stoplight Elements, ReDoc, Scalar or RapiDoc served automatically at
/docs - 📄 YAML Export — OpenAPI spec available at
/docs/openapi.yaml - 🚀 Low Overhead — Minimal runtime work beyond route registration and docs serving
go get github.com/oaswrap/spec/adapter/ginopenapipackage main
import (
"log"
"github.com/gin-gonic/gin"
"github.com/oaswrap/spec/adapter/ginopenapi"
"github.com/oaswrap/spec/option"
)
func main() {
e := gin.Default()
// Create a new OpenAPI router
r := ginopenapi.NewRouter(e,
option.WithTitle("My API"),
option.WithVersion("1.0.0"),
option.WithSecurity("bearerAuth", option.SecurityHTTPBearer("Bearer")),
)
// Add routes
v1 := r.Group("/api/v1")
v1.POST("/login", LoginHandler).With(
option.Summary("User login"),
option.Request(new(LoginRequest)),
option.Response(200, new(LoginResponse)),
)
auth := v1.Group("/", AuthMiddleware).With(
option.GroupSecurity("bearerAuth"),
)
auth.GET("/users/:id", GetUserHandler).With(
option.Summary("Get user by ID"),
option.Request(new(GetUserRequest)),
option.Response(200, new(User)),
)
log.Printf("🚀 OpenAPI docs available at: %s", "http://localhost:3000/docs")
if err := e.Run(":3000"); err != nil {
log.Fatal(err)
}
}
type LoginRequest struct {
Username string `json:"username" required:"true"`
Password string `json:"password" required:"true"`
}
type LoginResponse struct {
Token string `json:"token"`
}
type GetUserRequest struct {
ID string `path:"id" uri:"id" required:"true"`
}
type User struct {
ID string `json:"id"`
Name string `json:"name"`
}
func AuthMiddleware(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader != "" && authHeader == "Bearer example-token" {
c.Next()
} else {
c.JSON(401, gin.H{"error": "Unauthorized"})
c.Abort()
}
}
func LoginHandler(c *gin.Context) {
var req LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, map[string]string{"error": "Invalid request"})
return
}
// Simulate login logic
c.JSON(200, LoginResponse{Token: "example-token"})
}
func GetUserHandler(c *gin.Context) {
var req GetUserRequest
if err := c.ShouldBindUri(&req); err != nil {
c.JSON(400, map[string]string{"error": "Invalid request"})
return
}
// Simulate fetching user by ID
user := User{ID: req.ID, Name: "John Doe"}
c.JSON(200, user)
}When you create a ginopenapi router, the following endpoints are automatically available:
/docs— Interactive UI documentation/docs/openapi.yaml— Raw OpenAPI specification in YAML format
If you want to disable the built-in UI, you can do so by passing option.WithDisableDocs() when creating the router:
r := ginopenapi.NewRouter(e,
option.WithTitle("My API"),
option.WithVersion("1.0.0"),
option.WithDisableDocs(),
)Choose from multiple UI options, powered by oaswrap/spec-ui:
- Stoplight Elements — Modern, clean design (default)
- Swagger UI — Classic interface with try-it functionality
- ReDoc — Three-panel responsive layout
- Scalar — Beautiful and fast interface
- RapiDoc — Highly customizable
r := ginopenapi.NewRouter(e,
option.WithTitle("My API"),
option.WithVersion("1.0.0"),
option.WithScalar(), // Use Scalar as the documentation UI
)By default, UI providers use CDN assets to keep binaries small.
To serve embedded assets (offline mode), use option.WithUIOption(...) with the provider emb package directly:
import (
stoplightemb "github.com/oaswrap/spec-ui/stoplightemb"
)
// example:
option.WithUIOption(stoplightemb.WithUI())Use struct tags to generate detailed OpenAPI schemas. Note: These tags are used only for OpenAPI spec generation and documentation - they do not perform actual request validation.
type CreateProductRequest struct {
Name string `json:"name" required:"true" minLength:"1" maxLength:"100"`
Description string `json:"description" maxLength:"500"`
Price float64 `json:"price" required:"true" minimum:"0" maximum:"999999.99"`
Category string `json:"category" required:"true" enum:"electronics,books,clothing"`
Tags []string `json:"tags" maxItems:"10"`
InStock bool `json:"in_stock" default:"true"`
}Supported tags are implemented by oaswrap/spec directly. Common request tags include json, form, path, query, header, and cookie; common schema tags include description, format, default, example, enum, minimum, maximum, minLength, maxLength, minItems, maxItems, nullable, deprecated, readOnly, and writeOnly. See the root Reflection Tags section for the complete list.
Check out the examples directory for more complete implementations and use cases.
- Organize with Tags — Group related operations using
option.Tags() - Document Everything — Use
option.Summary()andoption.Description()for all routes - Define Error Responses — Include common error responses (400, 401, 404, 500)
- Document Schema Constraints — Use reflection tags to describe OpenAPI schema constraints; keep runtime validation in handlers or middleware
- Security First — Define and apply appropriate security schemes
- Version Your API — Use route groups for API versioning (
/api/v1,/api/v2)
- Spec: pkg.go.dev/github.com/oaswrap/spec
- Gin Adapter: pkg.go.dev/github.com/oaswrap/spec/adapter/ginopenapi
- Options: pkg.go.dev/github.com/oaswrap/spec/option
- Spec UI: pkg.go.dev/github.com/oaswrap/spec-ui
We welcome contributions! Please open issues and PRs at the main oaswrap/spec repository.