Skip to content

Commit 0e7fcc9

Browse files
committed
Update data structure and logic to handle both Swagger 2 and OpenAPI 3 documents
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
1 parent a637b92 commit 0e7fcc9

21 files changed

+2658
-128
lines changed

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# OpenAPI v2 object model [![Build Status](https://github.com/go-openapi/spec/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/spec/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/spec/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/spec)
1+
# OpenAPI v2/v3 object model [![Build Status](https://github.com/go-openapi/spec/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/spec/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/spec/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/spec)
22

33
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
44
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/spec/master/LICENSE)
@@ -15,7 +15,7 @@ This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
1515

1616
* What does this do?
1717

18-
> 1. This package knows how to marshal and unmarshal Swagger API specifications into a golang object model
18+
> 1. This package knows how to marshal and unmarshal Swagger and OpenAPI v3 API specifications into a golang object model
1919
> 2. It knows how to resolve $ref and expand them to make a single root document
2020
2121
* How does it play with the rest of the go-openapi packages ?
@@ -27,12 +27,14 @@ This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
2727
2828
* Does this library support OpenAPI 3?
2929

30-
> No.
31-
> This package currently only supports OpenAPI 2.0 (aka Swagger 2.0).
32-
> There is no plan to make it evolve toward supporting OpenAPI 3.x.
33-
> This [discussion thread](https://github.com/go-openapi/spec/issues/21) relates the full story.
34-
>
35-
> An early attempt to support Swagger 3 may be found at: https://github.com/go-openapi/spec3
30+
> **Yes!**
31+
> This package supports both OpenAPI 2.0 (aka Swagger 2.0) and OpenAPI 3.x (3.2.0).
32+
> Key changes in v3:
33+
> - `swagger: "2.0"``openapi: "3.x.x"`
34+
> - `definitions`, `parameters`, `responses``components/*`
35+
> - `host`, `basePath`, `schemes``servers[]`
36+
> - Body/form parameters → `requestBody`
37+
> - Response schemas → `content` with media types
3638
3739
* Does the unmarshaling support YAML?
3840

cache.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,10 @@ func initResolutionCache() {
6969

7070
func defaultResolutionCache() *simpleCache {
7171
return &simpleCache{store: map[string]any{
72-
"http://swagger.io/v2/schema.json": MustLoadSwagger20Schema(),
73-
"http://json-schema.org/draft-04/schema": MustLoadJSONSchemaDraft04(),
72+
"http://swagger.io/v2/schema.json": MustLoadSwagger20Schema(),
73+
"http://json-schema.org/draft-04/schema": MustLoadJSONSchemaDraft04(),
74+
"https://spec.openapis.org/oas/3.2/schema/2025-09-17": MustLoadOpenAPI32Schema(),
75+
"https://spec.openapis.org/oas/3.2/schema/2025-09-17#": MustLoadOpenAPI32Schema(),
7476
}}
7577
}
7678

components.go

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package spec
5+
6+
import (
7+
"encoding/json"
8+
9+
"github.com/go-openapi/jsonpointer"
10+
"github.com/go-openapi/swag/jsonutils"
11+
)
12+
13+
// Components holds a set of reusable objects for different aspects of the OAS.
14+
// All objects defined within the components object will have no effect on the API
15+
// unless they are explicitly referenced from properties outside the components object.
16+
//
17+
// For more information: https://spec.openapis.org/oas/v3.1.0#components-object
18+
type Components struct {
19+
VendorExtensible
20+
ComponentsProps
21+
}
22+
23+
// ComponentsProps describes the properties of a Components object
24+
type ComponentsProps struct {
25+
Schemas map[string]Schema `json:"schemas,omitempty"`
26+
Responses map[string]Response `json:"responses,omitempty"`
27+
Parameters map[string]Parameter `json:"parameters,omitempty"`
28+
Examples map[string]Example `json:"examples,omitempty"`
29+
RequestBodies map[string]RequestBody `json:"requestBodies,omitempty"`
30+
Headers map[string]Header `json:"headers,omitempty"`
31+
SecuritySchemes map[string]SecurityScheme `json:"securitySchemes,omitempty"`
32+
Links map[string]Link `json:"links,omitempty"`
33+
Callbacks map[string]Callback `json:"callbacks,omitempty"`
34+
}
35+
36+
// JSONLookup look up a value by the json property name
37+
func (c Components) JSONLookup(token string) (any, error) {
38+
if ex, ok := c.Extensions[token]; ok {
39+
return &ex, nil
40+
}
41+
r, _, err := jsonpointer.GetForToken(c.ComponentsProps, token)
42+
return r, err
43+
}
44+
45+
// MarshalJSON marshals this to JSON
46+
func (c Components) MarshalJSON() ([]byte, error) {
47+
b1, err := json.Marshal(c.ComponentsProps)
48+
if err != nil {
49+
return nil, err
50+
}
51+
b2, err := json.Marshal(c.VendorExtensible)
52+
if err != nil {
53+
return nil, err
54+
}
55+
return jsonutils.ConcatJSON(b1, b2), nil
56+
}
57+
58+
// UnmarshalJSON unmarshals this from JSON
59+
func (c *Components) UnmarshalJSON(data []byte) error {
60+
if err := json.Unmarshal(data, &c.ComponentsProps); err != nil {
61+
return err
62+
}
63+
return json.Unmarshal(data, &c.VendorExtensible)
64+
}
65+
66+
// Link represents a possible design-time link for a response.
67+
//
68+
// For more information: https://spec.openapis.org/oas/v3.1.0#link-object
69+
type Link struct {
70+
Refable
71+
VendorExtensible
72+
LinkProps
73+
}
74+
75+
// LinkProps describes the properties of a Link
76+
type LinkProps struct {
77+
OperationRef string `json:"operationRef,omitempty"`
78+
OperationID string `json:"operationId,omitempty"`
79+
Parameters map[string]any `json:"parameters,omitempty"`
80+
RequestBody any `json:"requestBody,omitempty"`
81+
Description string `json:"description,omitempty"`
82+
Server *Server `json:"server,omitempty"`
83+
}
84+
85+
// JSONLookup look up a value by the json property name
86+
func (l Link) JSONLookup(token string) (any, error) {
87+
if ex, ok := l.Extensions[token]; ok {
88+
return &ex, nil
89+
}
90+
r, _, err := jsonpointer.GetForToken(l.LinkProps, token)
91+
return r, err
92+
}
93+
94+
// MarshalJSON marshals this to JSON
95+
func (l Link) MarshalJSON() ([]byte, error) {
96+
b1, err := json.Marshal(l.Refable)
97+
if err != nil {
98+
return nil, err
99+
}
100+
b2, err := json.Marshal(l.LinkProps)
101+
if err != nil {
102+
return nil, err
103+
}
104+
b3, err := json.Marshal(l.VendorExtensible)
105+
if err != nil {
106+
return nil, err
107+
}
108+
return jsonutils.ConcatJSON(b1, b2, b3), nil
109+
}
110+
111+
// UnmarshalJSON unmarshals this from JSON
112+
func (l *Link) UnmarshalJSON(data []byte) error {
113+
if err := json.Unmarshal(data, &l.Refable); err != nil {
114+
return err
115+
}
116+
if err := json.Unmarshal(data, &l.LinkProps); err != nil {
117+
return err
118+
}
119+
return json.Unmarshal(data, &l.VendorExtensible)
120+
}
121+
122+
// Callback is a map of possible out-of band callbacks related to the parent operation.
123+
//
124+
// For more information: https://spec.openapis.org/oas/v3.1.0#callback-object
125+
type Callback struct {
126+
Refable
127+
VendorExtensible
128+
CallbackProps
129+
}
130+
131+
// CallbackProps describes the properties of a Callback
132+
type CallbackProps struct {
133+
Expressions map[string]PathItem `json:"-"`
134+
}
135+
136+
// JSONLookup look up a value by the json property name
137+
func (c Callback) JSONLookup(token string) (any, error) {
138+
if ex, ok := c.Extensions[token]; ok {
139+
return &ex, nil
140+
}
141+
if pi, ok := c.Expressions[token]; ok {
142+
return pi, nil
143+
}
144+
return nil, nil
145+
}
146+
147+
// MarshalJSON marshals this to JSON
148+
func (c Callback) MarshalJSON() ([]byte, error) {
149+
b1, err := json.Marshal(c.Refable)
150+
if err != nil {
151+
return nil, err
152+
}
153+
b2, err := json.Marshal(c.Expressions)
154+
if err != nil {
155+
return nil, err
156+
}
157+
b3, err := json.Marshal(c.VendorExtensible)
158+
if err != nil {
159+
return nil, err
160+
}
161+
return jsonutils.ConcatJSON(b1, b2, b3), nil
162+
}
163+
164+
// UnmarshalJSON unmarshals this from JSON
165+
func (c *Callback) UnmarshalJSON(data []byte) error {
166+
if err := json.Unmarshal(data, &c.Refable); err != nil {
167+
return err
168+
}
169+
if err := json.Unmarshal(data, &c.Expressions); err != nil {
170+
return err
171+
}
172+
return json.Unmarshal(data, &c.VendorExtensible)
173+
}

embed.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@ func jsonschemaDraft04JSONBytes() ([]byte, error) {
1818
func v2SchemaJSONBytes() ([]byte, error) {
1919
return assets.ReadFile(path.Join("schemas", "v2", "schema.json"))
2020
}
21+
22+
func v3SchemaJSONBytes() ([]byte, error) {
23+
return assets.ReadFile(path.Join("schemas", "v3", "schema.json"))
24+
}

0 commit comments

Comments
 (0)