Skip to content

Add OpenAPI 3.1.1 support to Goa framework#3755

Closed
gobijan wants to merge 3 commits into
goadesign:v3from
gobijan:v3
Closed

Add OpenAPI 3.1.1 support to Goa framework#3755
gobijan wants to merge 3 commits into
goadesign:v3from
gobijan:v3

Conversation

@gobijan
Copy link
Copy Markdown

@gobijan gobijan commented Aug 8, 2025

This commit upgrades the OpenAPI specification support from 3.0.3 to 3.1.1, introducing several new features and improvements while maintaining full backward compatibility with OpenAPI 2.0 (Swagger) and 3.0 specifications.

Key Changes:

  • Upgrade OpenAPI version from 3.0.3 to 3.1.1 across all packages
  • Add webhook support for documenting outgoing HTTP requests
  • Implement JSON Schema 2020-12 dialect compatibility
  • Update nullable type handling to use type arrays instead of nullable keyword

New Features:

  • Webhook DSL and expression types for defining webhook operations
  • Info.Summary field for providing brief API descriptions
  • License.Identifier field for SPDX license identifiers
  • Components.PathItems for reusable path item definitions
  • JSONSchemaDialect field in root OpenAPI object

Implementation Details:

  • Added Webhook() DSL function for defining webhook endpoints
  • Created WebhookExpr and HTTPWebhookExpr expression types
  • Updated Schema type handling for OpenAPI 3.1 nullable support
  • Fixed JSON marshaling to properly emit type fields
  • Added comprehensive nil safety checks throughout

Code Quality Improvements:

  • Fixed slice initialization anti-patterns
  • Moved state mutations from Validate to Prepare methods
  • Enhanced nil safety in webhook operations
  • Cleaned up unnecessary comments and improved code organization

Testing:

  • Updated all golden test files for v2 and v3 packages
  • Verified backward compatibility with existing specifications
  • Validated webhook functionality with new test cases
  • Ensured proper JSON Schema 2020-12 dialect output

The implementation maintains full backward compatibility while enabling developers to leverage the latest OpenAPI 3.1.1 features for more comprehensive API documentation.

Let me know what you think.

Issue: #3758

This commit upgrades the OpenAPI specification support from 3.0.3 to 3.1.1,
introducing several new features and improvements while maintaining full
backward compatibility with OpenAPI 2.0 (Swagger) and 3.0 specifications.

Key Changes:
- Upgrade OpenAPI version from 3.0.3 to 3.1.1 across all packages
- Add webhook support for documenting outgoing HTTP requests
- Implement JSON Schema 2020-12 dialect compatibility
- Update nullable type handling to use type arrays instead of nullable keyword

New Features:
- Webhook DSL and expression types for defining webhook operations
- Info.Summary field for providing brief API descriptions
- License.Identifier field for SPDX license identifiers
- Components.PathItems for reusable path item definitions
- JSONSchemaDialect field in root OpenAPI object

Implementation Details:
- Added Webhook() DSL function for defining webhook endpoints
- Created WebhookExpr and HTTPWebhookExpr expression types
- Updated Schema type handling for OpenAPI 3.1 nullable support
- Fixed JSON marshaling to properly emit type fields
- Added comprehensive nil safety checks throughout

Code Quality Improvements:
- Fixed slice initialization anti-patterns
- Moved state mutations from Validate to Prepare methods
- Enhanced nil safety in webhook operations
- Cleaned up unnecessary comments and improved code organization

Testing:
- Updated all golden test files for v2 and v3 packages
- Verified backward compatibility with existing specifications
- Validated webhook functionality with new test cases
- Ensured proper JSON Schema 2020-12 dialect output

The implementation maintains full backward compatibility while enabling
developers to leverage the latest OpenAPI 3.1.1 features for more
comprehensive API documentation.
@gobijan
Copy link
Copy Markdown
Author

gobijan commented Aug 8, 2025

Works For Me™

I used my fork to generate Webhook Documentation in the portable version of my https://sunnybox.io email api (see screenshot):

Screenshot 2025-08-08 at 21 42 57

@gobijan gobijan mentioned this pull request Aug 10, 2025
@gobijan
Copy link
Copy Markdown
Author

gobijan commented Aug 10, 2025

I created the tracking Issue: #3758

Copy link
Copy Markdown
Member

@raphael raphael left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR! Adding support for OpenAPI 3.1 would be a great addition. I left a few comments below that would be good to address before we can merge this PR. Additionally:

  • We probably need to address is backwards compatibility. I don't think we can assume all Goa users can just bump up to 3.1 (there might be tools consuming the generated OpenAPI spec that might not support 3.1 yet or might behave differently with it). So we probably need to support both 3.0.3 and 3.1.1 and generate e.g. openapi31.json and .yaml.

  • It would be nice to see if we can reuse existing DSL functions instead of introducing a complete set for Webhooks. For example Description instead of WebhookDescription, Payload instead of WebhookPayload etc. Also the way the HTTP verb and path is set should mirror how it's done in HTTP.

  • There are a few lint issues - use make locally to ensure the build passes.

Comment thread expr/http_service.go
}

// validateWebhooks validates webhooks
func (svc *HTTPServiceExpr) validateWebhooks(verr *eval.ValidationErrors) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really needed? seems like the DSL should ensure there's a parent?

Comment thread expr/http_service.go
}

// Prepare webhooks - map service webhooks to HTTP webhooks
for _, w := range svc.ServiceExpr.Webhooks {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we really need transport agnostic webhooks? seems pretty HTTP specific by definition. Maybe we just have HTTPWebhooks (which we could just call Webhooks)

Comment thread expr/http_service.go
}

// WebhookFor creates or returns the HTTP webhook for the given webhook expression.
func (svc *HTTPServiceExpr) WebhookFor(w *WebhookExpr) *HTTPWebhookExpr {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't used I don't think

// GenerateForOpenAPIv2 indicates whether we're generating for OpenAPI v2 (Swagger)
// When true, schemas will use v2 compatible format (single example, string type)
// When false, schemas will use v3.1 format (examples array, type arrays for nullable)
GenerateForOpenAPIv2 bool
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be a lot cleaner to bite the bullet and create a separate struct. Maybe the v2 and v3.1 structs can embed a common struct for most things which would implement the common behavior. Having this global variable trigger different behavior isn't great.

@gobijan
Copy link
Copy Markdown
Author

gobijan commented Aug 28, 2025

Hmm... maybe open a new branch where you lay out the foundation? I'd be happy to contribute and fully understand that the code should adhere to your standards and overall design. I'm asking myself if it makes sense to continue with this one as you have a better feel for the project etc.

@gobijan
Copy link
Copy Markdown
Author

gobijan commented Aug 28, 2025

Also sorry that it took me so long to respond. I've been under crazy workload.

@raphael
Copy link
Copy Markdown
Member

raphael commented Aug 28, 2025

No worries, that makes sense. I'll take over - thank you for the initial pass!

@raphael raphael closed this Aug 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants