Advanced Usage
4 minute read
Learn about advanced features including custom operation IDs, extensions, and strict downlevel mode.
Custom Operation IDs
By default, operation IDs are auto-generated from the HTTP method and path. You can override this behavior.
Auto-Generated Operation IDs
openapi.GET("/users/:id",
openapi.WithSummary("Get user"),
openapi.WithResponse(200, User{}),
)
// Generated operation ID: "getUsers_id"
openapi.POST("/users",
openapi.WithSummary("Create user"),
openapi.WithRequest(CreateUserRequest{}),
openapi.WithResponse(201, User{}),
)
// Generated operation ID: "postUsers"
Custom Operation IDs
Override with WithOperationID():
openapi.GET("/users/:id",
openapi.WithOperationID("getUserById"),
openapi.WithSummary("Get user"),
openapi.WithResponse(200, User{}),
)
openapi.POST("/users",
openapi.WithOperationID("createNewUser"),
openapi.WithSummary("Create user"),
openapi.WithRequest(CreateUserRequest{}),
openapi.WithResponse(201, User{}),
)
Operation ID Best Practices
- Use camelCase - Consistent with most API conventions.
- Be descriptive -
getUserByIdrather thangetUser1. - Avoid conflicts - Ensure unique IDs across all operations.
- Consider generation - Some tools generate client code from operation IDs.
Extensions
OpenAPI allows custom x-* extensions for vendor-specific metadata.
Root-Level Extensions
Add extensions to the root of the specification:
api := openapi.MustNew(
openapi.WithTitle("My API", "1.0.0"),
openapi.WithExtension("x-api-version", "v2"),
openapi.WithExtension("x-custom-feature", true),
openapi.WithExtension("x-rate-limit-config", map[string]interface{}{
"requests": 100,
"period": "1m",
}),
)
Operation Extensions
Add extensions to specific operations.
openapi.GET("/users",
openapi.WithSummary("List users"),
openapi.WithOperationExtension("x-rate-limit", 100),
openapi.WithOperationExtension("x-cache-ttl", 300),
openapi.WithOperationExtension("x-internal-only", false),
openapi.WithResponse(200, []User{}),
)
Extension Naming Rules
- Must start with
x-- Required by OpenAPI specification - Reserved prefixes -
x-oai-andx-oas-are reserved in 3.1.x - Case-sensitive -
x-Customandx-customare different
Extension Validation
Extensions are validated:
// Valid
openapi.WithExtension("x-custom", "value")
// Invalid - doesn't start with x-
openapi.WithExtension("custom", "value") // Error
// Invalid - reserved prefix in 3.1.x
openapi.WithExtension("x-oai-custom", "value") // Filtered out in 3.1.x
Common Extension Use Cases
// API versioning
openapi.WithExtension("x-api-version", "2.0")
// Rate limiting
openapi.WithOperationExtension("x-rate-limit", map[string]interface{}{
"requests": 100,
"window": "1m",
})
// Caching
openapi.WithOperationExtension("x-cache", map[string]interface{}{
"ttl": 300,
"vary": []string{"Authorization", "Accept-Language"},
})
// Internal metadata
openapi.WithOperationExtension("x-internal", map[string]interface{}{
"team": "platform",
"cost": "low",
})
// Feature flags
openapi.WithOperationExtension("x-feature-flag", "new-user-flow")
// Code generation hints
openapi.WithOperationExtension("x-codegen", map[string]interface{}{
"methodName": "customMethodName",
"packageName": "users",
})
Strict Downlevel Mode
By default, using 3.1 features with a 3.0 target generates warnings. Enable strict mode to error instead:
Default Behavior (Warnings)
api := openapi.MustNew(
openapi.WithTitle("API", "1.0.0"),
openapi.WithVersion(openapi.V30x),
openapi.WithInfoSummary("Summary"), // 3.1-only feature
)
result, err := api.Generate(context.Background(), ops...)
// err is nil (generation succeeds)
// result.Warnings contains warning about info.summary being dropped
Strict Mode (Errors)
api := openapi.MustNew(
openapi.WithTitle("API", "1.0.0"),
openapi.WithVersion(openapi.V30x),
openapi.WithStrictDownlevel(true), // Enable strict mode
openapi.WithInfoSummary("Summary"), // This will cause an error
)
result, err := api.Generate(context.Background(), ops...)
// err is non-nil (generation fails)
When to Use Strict Mode
Use strict mode when:
- Enforcing version compliance - Prevent accidental 3.1 feature usage
- CI/CD validation - Fail builds on version violations
- Team standards - Ensure consistent OpenAPI version usage
- Client compatibility - Target clients require strict 3.0 compliance
Don’t use strict mode when:
- Graceful degradation - You’re okay with features being dropped
- Development - Exploring features without hard errors
- Flexible deployments - Different environments support different versions
Features Affected by Strict Mode
3.1-only features that trigger strict mode:
WithInfoSummary()- Short API summaryWithLicenseIdentifier()- SPDX license identifier- Webhooks - Webhook definitions
- Mutual TLS -
mutualTLSsecurity scheme constin schemas - JSON Schemaconstkeyword- Multiple
examples- Multiple schema examples
Complete Advanced Example
package main
import (
"context"
"fmt"
"log"
"rivaas.dev/openapi"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
type CreateUserRequest struct {
Name string `json:"name" validate:"required"`
}
func main() {
api := openapi.MustNew(
// Basic configuration
openapi.WithTitle("Advanced API", "1.0.0"),
openapi.WithVersion(openapi.V30x),
// Root-level extensions
openapi.WithExtension("x-api-version", "v2"),
openapi.WithExtension("x-environment", "production"),
openapi.WithExtension("x-service-info", map[string]interface{}{
"team": "platform",
"repository": "github.com/example/api",
}),
// Strict mode (optional)
openapi.WithStrictDownlevel(false), // Allow graceful degradation
)
result, err := api.Generate(context.Background(),
// Custom operation IDs
openapi.GET("/users/:id",
openapi.WithOperationID("getUserById"),
openapi.WithSummary("Get user by ID"),
// Operation extensions
openapi.WithOperationExtension("x-rate-limit", 100),
openapi.WithOperationExtension("x-cache-ttl", 300),
openapi.WithOperationExtension("x-internal-team", "users"),
openapi.WithResponse(200, User{}),
),
openapi.POST("/users",
openapi.WithOperationID("createUser"),
openapi.WithSummary("Create a new user"),
// Different extensions per operation
openapi.WithOperationExtension("x-rate-limit", 10),
openapi.WithOperationExtension("x-feature-flag", "new-user-flow"),
openapi.WithOperationExtension("x-mutation", true),
openapi.WithRequest(CreateUserRequest{}),
openapi.WithResponse(201, User{}),
),
openapi.PUT("/users/:id",
openapi.WithOperationID("updateUser"),
openapi.WithSummary("Update user"),
openapi.WithOperationExtension("x-rate-limit", 50),
openapi.WithOperationExtension("x-mutation", true),
openapi.WithRequest(CreateUserRequest{}),
openapi.WithResponse(200, User{}),
),
openapi.DELETE("/users/:id",
openapi.WithOperationID("deleteUser"),
openapi.WithSummary("Delete user"),
openapi.WithOperationExtension("x-rate-limit", 10),
openapi.WithOperationExtension("x-mutation", true),
openapi.WithOperationExtension("x-dangerous", true),
openapi.WithResponse(204, nil),
),
)
if err != nil {
log.Fatal(err)
}
// Check for warnings
if len(result.Warnings) > 0 {
fmt.Printf("Generated with %d warnings:\n", len(result.Warnings))
for _, warn := range result.Warnings {
fmt.Printf(" - %s\n", warn.Message())
}
}
fmt.Printf("Generated %d byte specification\n", len(result.JSON))
}
Best Practices
Operation IDs
- Be consistent - Use the same naming convention across all operations
- Make them unique - Avoid duplicate operation IDs
- Consider clients - Generated client libraries use these names
- Document the convention - Help team members follow the pattern
Extensions
- Use sparingly - Only add extensions when necessary
- Document them - Explain what custom extensions mean
- Validate format - Ensure extensions follow your schema
- Version them - Consider versioning extension formats
- Tool compatibility - Check if tools support your extensions
Strict Mode
- Enable in CI/CD - Catch version issues early
- Document the choice - Explain why strict mode is enabled/disabled
- Test both modes - Ensure graceful degradation works if disabled
- Communicate clearly - Make version requirements explicit
Next Steps
- See Examples for complete usage patterns
- Review Diagnostics for warning handling
- Check Validation for specification validation
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.