grape-swagger icon indicating copy to clipboard operation
grape-swagger copied to clipboard

Add OpenAPI 3.0/3.1 support with backward-compatible architecture

Open numbata opened this issue 2 months ago • 3 comments

Summary

This PR adds comprehensive OpenAPI 3.0 and 3.1 support to grape-swagger through a new layered architecture, while maintaining full backward compatibility with existing Swagger 2.0 functionality.

This implementation follows the approach outlined in #928 (comment):

Rather than maintaining parallel implementations... separating the process of gathering endpoint information from the process of schema generation, possibly by using intermediate structures.

Instead of duplicating the Swagger 2.0 code and modifying it for OAS3 (which creates maintenance challenges with "two separate codebases doing almost the same job"), this PR introduces:

  1. Intermediate OpenAPI Model Layer - Document, Schema, Operation, Parameter, etc.
  2. Single Builder - OpenAPI::Builder::Spec that populates the model from Grape routes
  3. Version-specific Exporters - Swagger2, OAS30, OAS31 that serialize the model to the target format

This architecture makes it easy to maintain both versions and leverage OpenAPI 3.x schema composition benefits.

Background

This architecture was initially prototyped in grape-oas as a standalone gem to validate the approach of using intermediate structures for multi-version OpenAPI support. This PR integrates that proven pattern directly into grape-swagger.

Usage

# Swagger 2.0 (default, unchanged)
add_swagger_documentation

# OpenAPI 3.0
add_swagger_documentation(openapi_version: '3.0')

# OpenAPI 3.1
add_swagger_documentation(openapi_version: '3.1')

Key Features

OpenAPI 3.x Support

  • requestBody: Body and formData parameters converted to OAS3 requestBody format
  • components/schemas: Definitions moved to components with proper $ref paths
  • servers: Host/basePath/schemes converted to servers array
  • securitySchemes: Security definitions moved to components
  • Parameter schemas: Inline types wrapped in schema objects

OAS 3.1 Specific Features

  • jsonSchemaDialect configuration option
  • webhooks support
  • type: ["string", "null"] for nullable (instead of nullable: true)
  • License identifier field (SPDX)

Nullable Handling

Both syntaxes work across all versions:

Syntax Swagger 2.0 OAS 3.0 OAS 3.1
documentation: { nullable: true } x-nullable nullable: true type: ["string", "null"]
documentation: { x: { nullable: true } } x-nullable nullable: true type: ["string", "null"]

Architecture

Grape Routes
     │
     ▼
┌─────────────────────────────┐
│  Builder::Spec              │  ← Builds OpenAPI Document model
│  (lib/grape-swagger/openapi)│
└─────────────────────────────┘
     │
     ▼
┌─────────────────────────────┐
│  OpenAPI Model Layer        │  ← Intermediate structures (Document, Schema, etc.)
│  (Document, Schema, etc.)   │
└─────────────────────────────┘
     │
     ├──────────────┬──────────────┐
     ▼              ▼              ▼
┌──────────┐  ┌──────────┐  ┌──────────┐
│ Swagger2 │  │  OAS30   │  │  OAS31   │  ← Version-specific exporters
│ Exporter │  │ Exporter │  │ Exporter │
└──────────┘  └──────────┘  └──────────┘

This separation enables:

  • Single source of truth for route parsing logic
  • Easy version-specific handling in exporters
  • Future extensibility for new OpenAPI versions or custom formats
  • Potential for DrySchema integration as schema objects (future enhancement)

Backward Compatibility

  • ✅ Default behavior unchanged (Swagger 2.0)
  • ✅ All existing configuration options work
  • ✅ Model parsers (grape-entity, representable) work unchanged
  • x: { nullable: true } syntax migrates seamlessly to OAS 3.x
  • ✅ Swagger 2.0 uses x-nullable extension (not nullable)
  • ✅ License identifier excluded from Swagger 2.0 output

Test Plan

  • [x] All existing Swagger 2.0 tests pass
  • [x] New OAS 3.0 integration tests
  • [x] New OAS 3.1 feature tests
  • [x] Nullable handling tests for all versions
  • [x] Backward compatibility tests for x: { nullable: true }
  • [x] Security schemes, file uploads, nested entities tested

Future Enhancements

With this architecture in place, future work could include:

  • DryValidation/DrySchema support for request parameters (as separate model parser gem)
  • Additional OpenAPI 3.1 features (pathItemObject in webhooks, etc.)

numbata avatar Dec 07 '25 03:12 numbata

This is pretty major, @LeFnord are you around to take a look?

dblock avatar Dec 10 '25 13:12 dblock

will have a deeper look on the weekend

LeFnord avatar Dec 10 '25 14:12 LeFnord

and yeah disable danger for the moment

LeFnord avatar Dec 14 '25 17:12 LeFnord