Converter Package Deep Dive
Try it Online
No installation required! Try the converter in your browser →
The converter package provides version conversion for OpenAPI Specification documents, supporting bidirectional conversion between OAS 2.0 and OAS 3.x.
Table of Contents
- Overview
- Key Concepts
- API Styles
- Practical Examples
- Conversion Details
- Version-Specific Considerations
- Common Pitfalls and Solutions
- Loss of Fidelity
- Overlay Integration
- Configuration Reference
- Best Practices
Overview
The converter performs best-effort conversion with detailed issue tracking. Features converted include servers, schemas, parameters, security schemes, and request/response bodies. It preserves the input file format (JSON or YAML) for output consistency.
Supported conversions: - OAS 2.0 (Swagger) -> OAS 3.0.x / 3.1.x - OAS 3.0.x / 3.1.x -> OAS 2.0 (Swagger)
Key Concepts
Issue Severity Levels
| Severity | Description |
|---|---|
| Info | Conversion choices and decisions made |
| Warning | Lossy conversions where data may be simplified |
| Critical | Features that cannot be converted |
Conversion Philosophy
The converter follows these principles:
- Best-effort conversion: Convert as much as possible, track what cannot be converted
- Transparency: Every conversion decision is recorded as an issue
- Reversibility awareness: Some conversions are lossy and cannot be reversed
- Version detection: Automatically detect source version and validate target version
What Cannot Convert
OAS 3.x -> OAS 2.0: - Webhooks (3.1+ only) - Callbacks - Links - TRACE HTTP method - Cookie parameters - Multiple servers (only first is used) - Content negotiation complexity
OAS 2.0 -> OAS 3.x:
- collectionFormat (may not map perfectly to style/explode)
- allowEmptyValue (deprecated in 3.x)
- File upload patterns differ significantly
API Styles
See also: Basic example, Handling issues example, Complex conversion example on pkg.go.dev
Functional Options (Recommended)
result, err := converter.ConvertWithOptions(
converter.WithFilePath("swagger.yaml"),
converter.WithTargetVersion("3.0.3"),
)
if err != nil {
log.Fatal(err)
}
Struct-Based (Reusable)
c := converter.New()
c.StrictMode = false
result1, _ := c.Convert("api1.yaml", "3.0.3")
result2, _ := c.Convert("api2.yaml", "3.0.3")
Pre-Parsed Documents
parseResult, _ := parser.ParseWithOptions(parser.WithFilePath("swagger.yaml"))
result, _ := converter.ConvertWithOptions(
converter.WithParsed(*parseResult),
converter.WithTargetVersion("3.0.3"),
)
Practical Examples
OAS 2.0 to OAS 3.0 Conversion
This is the most common conversion scenario - upgrading legacy Swagger specs:
package main
import (
"fmt"
"log"
"os"
"github.com/erraggy/oastools/converter"
)
func main() {
// Convert Swagger 2.0 to OpenAPI 3.0.3
result, err := converter.ConvertWithOptions(
converter.WithFilePath("swagger.yaml"),
converter.WithTargetVersion("3.0.3"),
)
if err != nil {
log.Fatal(err)
}
// Check for issues
fmt.Printf("Conversion complete: %d info, %d warnings, %d critical\n",
result.InfoCount, result.WarningCount, result.CriticalCount)
// Review any warnings or critical issues
for _, issue := range result.Issues {
if issue.Severity != "info" {
fmt.Printf("[%s] %s: %s\n", issue.Severity, issue.Location, issue.Message)
}
}
// Write the result
data, _ := result.Marshal()
os.WriteFile("openapi.yaml", data, 0644)
}
Example Input (swagger.yaml):
swagger: "2.0"
info:
title: Pet Store API
version: "1.0.0"
host: api.petstore.io
basePath: /v1
schemes:
- https
consumes:
- application/json
produces:
- application/json
paths:
/pets:
get:
operationId: listPets
parameters:
- name: limit
in: query
type: integer
format: int32
responses:
200:
description: A list of pets
schema:
type: array
items:
$ref: '#/definitions/Pet'
post:
operationId: createPet
parameters:
- name: body
in: body
required: true
schema:
$ref: '#/definitions/NewPet'
responses:
201:
description: Pet created
schema:
$ref: '#/definitions/Pet'
definitions:
Pet:
type: object
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
NewPet:
type: object
required:
- name
properties:
name:
type: string
tag:
type: string
Generated Output (openapi.yaml):
openapi: 3.0.3
info:
title: Pet Store API
version: "1.0.0"
servers:
- url: https://api.petstore.io/v1
paths:
/pets:
get:
operationId: listPets
parameters:
- name: limit
in: query
schema:
type: integer
format: int32
responses:
'200':
description: A list of pets
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
post:
operationId: createPet
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/NewPet'
responses:
'201':
description: Pet created
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
components:
schemas:
Pet:
type: object
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
NewPet:
type: object
required:
- name
properties:
name:
type: string
tag:
type: string
OAS 3.0 to OAS 3.1 Conversion
Upgrading to take advantage of JSON Schema alignment:
result, err := converter.ConvertWithOptions(
converter.WithFilePath("openapi-3.0.yaml"),
converter.WithTargetVersion("3.1.0"),
)
if err != nil {
log.Fatal(err)
}
// 3.1 enables nullable via type arrays
// nullable: true becomes type: ["string", "null"]
fmt.Printf("Converted to %s\n", result.TargetVersion)
Key Changes in 3.0 -> 3.1:
- nullable: true is converted to type arrays: type: ["string", "null"]
- JSON Schema keywords like unevaluatedProperties become available
- Webhooks support is added
OAS 3.x to OAS 2.0 Downgrade
When you need to support older tooling:
result, err := converter.ConvertWithOptions(
converter.WithFilePath("openapi.yaml"),
converter.WithTargetVersion("2.0"),
converter.WithStrictMode(false), // Allow conversion despite critical issues
)
if err != nil {
log.Fatal(err)
}
// IMPORTANT: Check for critical issues - features that couldn't convert
if result.HasCriticalIssues() {
fmt.Println("WARNING: Some features could not be converted:")
for _, issue := range result.Issues {
if issue.Severity == "critical" {
fmt.Printf(" - %s: %s\n", issue.Location, issue.Message)
}
}
}
data, _ := result.Marshal()
os.WriteFile("swagger.yaml", data, 0644)
Handling Conversion Issues
result, _ := converter.ConvertWithOptions(
converter.WithFilePath("api.yaml"),
converter.WithTargetVersion("3.0.3"),
converter.WithIncludeInfo(true), // Include info-level issues for full visibility
)
// Categorize issues by type
var schemaIssues, pathIssues, securityIssues []converter.ConversionIssue
for _, issue := range result.Issues {
switch {
case strings.Contains(issue.Location, "schemas"):
schemaIssues = append(schemaIssues, issue)
case strings.Contains(issue.Location, "paths"):
pathIssues = append(pathIssues, issue)
case strings.Contains(issue.Location, "security"):
securityIssues = append(securityIssues, issue)
}
}
fmt.Printf("Schema issues: %d\n", len(schemaIssues))
fmt.Printf("Path issues: %d\n", len(pathIssues))
fmt.Printf("Security issues: %d\n", len(securityIssues))
Batch Conversion
Converting multiple files with consistent settings:
c := converter.New()
c.StrictMode = false
c.IncludeInfo = false // Only warnings and critical
files := []string{"api1.yaml", "api2.yaml", "api3.yaml"}
var totalCritical int
for _, file := range files {
result, err := c.Convert(file, "3.0.3")
if err != nil {
log.Printf("Failed to convert %s: %v", file, err)
continue
}
totalCritical += result.CriticalCount
// Write output with matching extension
outFile := strings.TrimSuffix(file, ".yaml") + "-v3.yaml"
data, _ := result.Marshal()
os.WriteFile(outFile, data, 0644)
fmt.Printf("Converted %s: %d warnings, %d critical\n",
file, result.WarningCount, result.CriticalCount)
}
fmt.Printf("\nTotal critical issues across all files: %d\n", totalCritical)
Conversion Details
OAS 2.0 -> OAS 3.0
| OAS 2.0 | OAS 3.0 | Notes |
|---|---|---|
host, basePath, schemes |
servers array |
Combined into URL template |
definitions |
components.schemas |
Reference paths updated |
parameters |
components.parameters |
Reference paths updated |
responses |
components.responses |
Reference paths updated |
securityDefinitions |
components.securitySchemes |
OAuth flows restructured |
consumes + body param |
requestBody.content |
Media types explicit |
produces + schema |
response.content |
Media types explicit |
type: file |
Binary string + format | type: string, format: binary |
collectionFormat |
style + explode |
Mapping varies by format |
Server URL Construction:
The converter combines OAS 2.0's separate fields into OAS 3.0's servers array:
# OAS 2.0
host: api.example.com
basePath: /v1
schemes:
- https
- http
# Converts to OAS 3.0
servers:
- url: https://api.example.com/v1
- url: http://api.example.com/v1
Request Body Extraction:
Body parameters are extracted and converted to requestBody:
# OAS 2.0
parameters:
- name: body
in: body
required: true
schema:
$ref: '#/definitions/Pet'
# Converts to OAS 3.0
requestBody:
required: true
content:
application/json: # From consumes
schema:
$ref: '#/components/schemas/Pet'
OAS 3.0 -> OAS 2.0
| OAS 3.0 | OAS 2.0 | Notes |
|---|---|---|
servers[0] |
host, basePath, schemes |
Only first server used |
components.schemas |
definitions |
Reference paths updated |
requestBody |
consumes + body parameter |
Single media type selected |
webhooks |
Dropped | Critical issue logged |
callbacks |
Dropped | Critical issue logged |
links |
Dropped | Critical issue logged |
cookie parameters |
Dropped | Critical issue logged |
| TRACE method | Dropped | Critical issue logged |
Server URL Decomposition:
# OAS 3.0
servers:
- url: https://api.example.com/v1
- url: http://staging.example.com/v2 # Ignored with warning
# Converts to OAS 2.0
host: api.example.com
basePath: /v1
schemes:
- https
OAS 3.0 -> OAS 3.1
| OAS 3.0 | OAS 3.1 | Notes |
|---|---|---|
nullable: true |
type: ["string", "null"] |
Type becomes array |
example |
examples (preferred) |
Can use either |
| N/A | webhooks |
Now available |
exclusiveMinimum: true |
exclusiveMinimum: <value> |
JSON Schema alignment |
OAS 3.1 -> OAS 3.0
| OAS 3.1 | OAS 3.0 | Notes |
|---|---|---|
type: ["string", "null"] |
type: string + nullable: true |
Array to boolean |
webhooks |
Dropped | Critical issue logged |
$comment |
Dropped | JSON Schema keyword |
unevaluatedProperties |
Dropped | JSON Schema keyword |
Version-Specific Considerations
Converting to OAS 3.0.x
Choose Your Patch Version:
- 3.0.0 - Initial release, use for maximum compatibility
- 3.0.1 - Clarifications only
- 3.0.2 - More clarifications
- 3.0.3 - Recommended - Most stable and widely supported
Watch For: - Security schemes with OAuth2 flows need careful mapping - Form data and file uploads have different patterns than 2.0 - Global consumes/produces become per-operation content types
Converting to OAS 3.1.x
JSON Schema Alignment: OAS 3.1 fully aligns with JSON Schema Draft 2020-12. This means:
typecan be an array:type: ["string", "null"]nullableis deprecated in favor of type arrays- New keywords available:
unevaluatedProperties,prefixItems, etc.
Webhooks: OAS 3.1+ introduces webhooks:
webhooks:
newPet:
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
responses:
'200':
description: Webhook processed
Choose Your Patch Version:
- 3.1.0 - Initial JSON Schema alignment
- 3.1.1 - Bug fixes and clarifications
Downgrading to OAS 2.0
Feature Loss: Expect to lose these OAS 3.x features: - Webhooks (cannot be represented) - Callbacks (cannot be represented) - Links (cannot be represented) - Cookie parameters (not supported) - Multiple content types per request/response (simplified)
Best Practices:
1. Always check HasCriticalIssues() after conversion
2. Review all critical issues to understand what was lost
3. Consider if the target tooling truly requires 2.0
4. Document the conversion limitations for API consumers
Common Pitfalls and Solutions
Pitfall 1: Ignoring Conversion Issues
Problem: Converting without checking the result for issues.
// WRONG: Ignoring issues
result, _ := converter.ConvertWithOptions(
converter.WithFilePath("api.yaml"),
converter.WithTargetVersion("2.0"),
)
data, _ := result.Marshal()
os.WriteFile("swagger.yaml", data, 0644)
// Webhooks, callbacks, links silently dropped!
Solution: Always check for issues, especially critical ones:
// CORRECT: Check issues
result, err := converter.ConvertWithOptions(
converter.WithFilePath("api.yaml"),
converter.WithTargetVersion("2.0"),
)
if err != nil {
log.Fatal(err)
}
if result.HasCriticalIssues() {
log.Printf("WARNING: %d features could not be converted", result.CriticalCount)
for _, issue := range result.Issues {
if issue.Severity == "critical" {
log.Printf(" %s: %s", issue.Location, issue.Message)
}
}
}
Pitfall 2: Strict Mode for Downgrades
Problem: Using strict mode when downgrading from 3.x to 2.0.
// WRONG: Strict mode fails on any critical issue
result, err := converter.ConvertWithOptions(
converter.WithFilePath("modern-api.yaml"), // Has webhooks
converter.WithTargetVersion("2.0"),
converter.WithStrictMode(true),
)
// Error: conversion has critical issues
Solution: Disable strict mode for downgrades, handle issues manually:
// CORRECT: Allow conversion, check issues
result, err := converter.ConvertWithOptions(
converter.WithFilePath("modern-api.yaml"),
converter.WithTargetVersion("2.0"),
converter.WithStrictMode(false),
)
if err != nil {
log.Fatal(err)
}
// Now check what was lost
for _, issue := range result.Issues {
if issue.Severity == "critical" {
log.Printf("Feature lost: %s", issue.Message)
}
}
Pitfall 3: Assuming Reference Paths Are Updated
Problem: Assuming only schema refs are updated.
All component references are updated during conversion:
# OAS 2.0 refs
$ref: '#/definitions/Pet'
$ref: '#/parameters/LimitParam'
$ref: '#/responses/NotFound'
# After conversion to OAS 3.0
$ref: '#/components/schemas/Pet'
$ref: '#/components/parameters/LimitParam'
$ref: '#/components/responses/NotFound'
The converter handles this automatically, but be aware when processing results.
Pitfall 4: Multiple Content Types
Problem: OAS 3.x allows multiple content types per operation; OAS 2.0 doesn't.
# OAS 3.0
requestBody:
content:
application/json:
schema: {...}
application/xml:
schema: {...}
text/plain:
schema: {...}
When downgrading to 2.0, only one content type is preserved (typically application/json). A warning issue is logged.
Solution: Review warnings and ensure the selected content type is appropriate:
for _, issue := range result.Issues {
if strings.Contains(issue.Message, "content type") {
log.Printf("Content type selection: %s", issue.Message)
}
}
Pitfall 5: OAuth Flow Differences
Problem: OAuth2 flows have different structures in 2.0 vs 3.0.
# OAS 2.0
securityDefinitions:
oauth2:
type: oauth2
flow: accessCode # Single flow
authorizationUrl: https://auth.example.com/authorize
tokenUrl: https://auth.example.com/token
scopes:
read: Read access
# OAS 3.0
components:
securitySchemes:
oauth2:
type: oauth2
flows: # Multiple flows possible
authorizationCode: # Renamed from 'accessCode'
authorizationUrl: https://auth.example.com/authorize
tokenUrl: https://auth.example.com/token
scopes:
read: Read access
The converter handles the flow name mapping (accessCode <-> authorizationCode, etc.).
Loss of Fidelity
Understanding what information is lost during conversion is crucial for making informed decisions.
OAS 3.x -> OAS 2.0 (Significant Loss)
| Feature | Impact | Mitigation |
|---|---|---|
| Webhooks | Complete loss | Document externally or use extensions |
| Callbacks | Complete loss | Document externally |
| Links | Complete loss | Document relationships externally |
| Cookie params | Complete loss | Use header params if possible |
| Multiple servers | Only first used | Document others externally |
| Multiple content types | First used | Ensure JSON is first if preferred |
| TRACE method | Dropped | Use custom extension if needed |
OAS 2.0 -> OAS 3.0 (Minimal Loss)
| Feature | Impact | Mitigation |
|---|---|---|
collectionFormat |
Mapped to style/explode | Verify serialization behavior |
allowEmptyValue |
Deprecated in 3.x | Behavior preserved if set |
| File type | Becomes binary string | Functionally equivalent |
OAS 3.0 <-> OAS 3.1 (Semantic Only)
| Feature | Impact | Mitigation |
|---|---|---|
nullable vs type array |
Semantic equivalence | Both work in most tools |
| JSON Schema keywords | Available in 3.1 only | Document requirements |
Measuring Fidelity Loss
result, _ := converter.ConvertWithOptions(
converter.WithFilePath("api.yaml"),
converter.WithTargetVersion("2.0"),
converter.WithIncludeInfo(true),
)
// Calculate fidelity score
totalFeatures := result.InfoCount + result.WarningCount + result.CriticalCount
if totalFeatures > 0 {
fidelity := 1.0 - (float64(result.CriticalCount) / float64(totalFeatures))
fmt.Printf("Conversion fidelity: %.1f%%\n", fidelity*100)
}
// Categorize losses
var losses = map[string]int{}
for _, issue := range result.Issues {
if issue.Severity == "critical" {
losses[issue.Location]++
}
}
fmt.Printf("Features lost by location: %v\n", losses)
Overlay Integration
Apply transformations before or after conversion:
result, err := converter.ConvertWithOptions(
converter.WithFilePath("swagger.yaml"),
converter.WithTargetVersion("3.0.3"),
converter.WithPreConversionOverlayFile("fix-v2.yaml"), // Fix v2-specific issues
converter.WithPostConversionOverlayFile("enhance.yaml"), // Add v3 extensions
)
Use Cases:
Pre-Conversion Overlays
Fix issues in the source document before conversion:
# fix-v2.yaml
overlay: 1.0.0
info:
title: Fix OAS 2.0 Issues
actions:
- target: $.info
update:
contact:
email: api@example.com
- target: $.paths./legacy-endpoint
remove: true # Remove deprecated endpoint before conversion
Post-Conversion Overlays
Add OAS 3.x specific enhancements:
# enhance.yaml
overlay: 1.0.0
info:
title: Add OAS 3.0 Enhancements
actions:
- target: $.servers
update:
- url: https://api.example.com/v3
description: Production
- url: https://staging.example.com/v3
description: Staging
- target: $.components.schemas.Pet
update:
x-oai-display-name: Pet Object
Configuration Reference
Functional Options
| Option | Description |
|---|---|
WithFilePath(path) |
Path to specification file |
WithParsed(result) |
Pre-parsed ParseResult |
WithTargetVersion(v) |
Target OAS version (e.g., "3.0.3", "2.0") |
WithStrictMode(bool) |
Fail on critical issues |
WithIncludeInfo(bool) |
Include info-level issues |
WithPreConversionOverlayFile(path) |
Overlay to apply before conversion |
WithPostConversionOverlayFile(path) |
Overlay to apply after conversion |
Converter Fields
| Field | Type | Default | Description |
|---|---|---|---|
StrictMode |
bool |
false |
Return error on critical issues |
IncludeInfo |
bool |
false |
Include info-level issues in result |
ConversionResult Fields
| Field | Type | Description |
|---|---|---|
Document |
any |
Converted document (OAS2Document or OAS3Document) |
TargetVersion |
string |
Target OAS version string |
Issues |
[]ConversionIssue |
All conversion issues |
CriticalCount |
int |
Number of critical issues |
WarningCount |
int |
Number of warnings |
InfoCount |
int |
Number of info items |
SourceFormat |
SourceFormat |
Original format (JSON/YAML) |
ConversionIssue Fields
| Field | Type | Description |
|---|---|---|
Severity |
string |
"info", "warning", or "critical" |
Location |
string |
JSON path to affected element |
Message |
string |
Human-readable description |
Code |
string |
Machine-readable issue code |
Best Practices
-
Always check issues - Use
HasCriticalIssues()and review warnings before using converted documents in production. -
Validate after conversion - The converted document may have structural issues that the converter cannot detect. Run through the validator:
-
Review critical issues - Critical issues indicate features that couldn't be converted. Document these for API consumers.
-
Use overlays for fixes - Pre/post conversion overlays can address gaps that the converter cannot handle automatically.
-
Preserve format - Use
result.Marshal()to maintain JSON/YAML consistency with the source document. -
Test round-trip conversions - If you need bidirectional compatibility, test converting A->B->A and verify the result.
-
Document version requirements - If your API requires 3.1+ features (webhooks, JSON Schema keywords), document this for consumers.
-
Use appropriate target versions:
- For maximum compatibility:
3.0.3or2.0 - For latest features:
3.1.0or3.2.0 -
For JSON Schema alignment:
3.1.0+ -
Handle nullable correctly - When converting 3.1 -> 3.0, verify that
nullable: trueis set where expected. -
Consider tooling compatibility - Some tools don't support 3.1+ yet. Check your toolchain before upgrading.
Learn More
For additional examples and complete API documentation:
- API Reference on pkg.go.dev - Complete API documentation with all examples
- Basic example - Convert OAS 2.0 to OAS 3.x
- Handling issues example - Process conversion issues by severity
- Complex conversion example - Advanced conversion scenarios