Releases: mattpolzin/OpenAPIKit
Noted (release candidate)
The first v3.0.0 Release Candidate.
This release comes with no breaking changes, bug fixes, or features above and beyond the latest Beta release but it introduces the first draft of a migration guide from v2.x to v3.x of OpenAPIKit.
Full Changelog: 3.0.0-beta.5...3.0.0-rc.1
Inline Skates
Big thanks to @nexon for jumping in and fixing a bug related to dereferencing callbacks within operations!
What's Changed
- fix double-validation error reporting (#309)
- Validation error improvements (#308)
- Support JSON Schema
const
. (#310) - Dereference Links (#311)
- Refactor vendor extensions on JSONSchema (#312)
- Dereference Callbacks (#314)
New Contributors
Noteworthy Differences
- Dereferenced JSON Schemas now have Vendor Extension support (only OpenAPIKit module, not OpenAPIKit30).
Link
s andCallbacksMap
s are now dereferenced when calling thedereferenced(in:)
andlocallyDereferenced()
methods.- JSON Schemas now support
const
(which is decoded as a single entry in theJSONSchema
type'sCoreContext
'sallowedValues
array). (only OpenAPIKit, not OpenAPIKit30).
Breaking Changes
JSONSchema
's initializers no longer takevendorExtensions
; instead, use the.with(vendorExtensions:)
function to add vendor extensions to a schema or build the vendor extensions into the schema'sCoreContext
to begin with. (only OpenAPIKit module, not OpenAPIKit30).- The
DereferencedOperation
type'scallbacks
property is now anOpenAPI.DereferencedCallbacksMap
instead of anOpenAPI.CallbacksMap
. - The
DereferencedResponse
type'slinks
property is now anOrderedDictionary<String, OpenAPI.Link>
instead of anOpenAPI.Link.Map
. - When a
JSONSchema
only has oneallowedValue
, it will now be encoded asconst
rather thanenum
. (only OpenAPIKit module, not OpenAPIKit30). - The
JSONSchema
type'scoreContext
accessor now gives a non-optional value because all cases have aCoreContext
. (only OpenAPIKit module, not OpenAPIKit30).
Full Changelog: 3.0.0-beta.4...3.0.0-beta.5
Flexibility is Key
What's Changed
- Optional responses within operations (#303)
- Add core context for
null
schemas (#305) - Optional paths within documents (#275)
New Contributors
- @noamalffasy made their first contribution in #275
Noteworthy Differences
Now paths within documents and responses within operations can both be omitted from documents (as they should be by the OpenAPI 3.1 specification). This only applies to the OpenAPIKit module, the OpenAPIKit30 module represents the OpenAPI 3.0 specification where these properties are still required. Instead of making the properties on the respective OpenAPIKit types Optional
, the empty collection of either paths
or responses
is now entirely omitted when encoding and an omitted value of either is decoded as the empty collection.
Breaking Changes
The following only apply to the OpenAPIKit module, not the OpenAPIKit30 module.
- The
.operationsContainResponses
validation is now opt-in instead of applied by default when validating. If you still want to ensure documents have responses in all Operation objects, tack the.operationsContainResponses
validation onto your validator, e.g.:try document.validate(using: Validator().validating(.operationsContainResponses))
. - The
null
case ofJSONSchema.Value
now has aCoreContext
property associated with it. If you pattern match on it, your code may need to change (though you are still allowed to match against just.null
and ignore the associated value if desirable). - The
JSONSchema.null
property that used to serve as a convenient way of creating a null-typeJSONSchema
is now a function. You can call it as.null()
which means most code will just need to gain the()
parens.
Full Changelog: 3.0.0-beta.3...3.0.0-beta.4
When Nothing is Everything
What's Changed
- fix bug with conversion of Server Variable enum from OAS 3.0 to 3.1 (#304)
Noteworthy Differences
N/A
Breaking Changes
N/A
Full Changelog: 3.0.0-beta.2...3.0.0-beta.3
Dynamite (3)
What's Changed
- Store component name as
x-component-name
when locally dereferencing an object (#295 / #296) - Add vendor extension support to
JSONSchema
(#297) - Support schema reference
description
overrides (#299) - Fix decoding of
explode
property on Headers (#302)
Noteworthy Differences
Dereferencing
When locally dereferencing part or all of the schema with the OpenAPIKit dereferenced(in:)
/dereferenced()
/locallyDereferenced()
functions, OpenAPIKit will store the name of the Component (the key within the Components Object) under a new x-component-name
vendor extension on the dereferenced value.
Example
let components = OpenAPI.Components(
examples: [
"test1": .init(value: .init("hello world"))
]
)
let content = try OpenAPI.Content(
schema: .string,
examples: [
"ex1": .reference(.component(named: "test1"))
]
).dereferenced(in: components)
XCTAssertEqual(
content.examples, [
"ex1": .init(
value: .init("hello world"),
vendorExtensions: ["x-component-name": "test1"]
)
]
)
Overriding description
on schema $ref
s
OpenAPIKit module only. Does not apply to OpenAPIKit30 module.
See the PR that introduced this change for some comments on why the current implementation was chosen.
OpenAPIKit will now encode/decode any CoreContext
JSONSchema
property alongside $ref
properties. This includes the description
, default
, examples
, deprecated
properties, and more.
If you use an OpenAPIKit method for locally dereferencing (e.g. the OpenAPI.Document
type's locallyDerefenced()
method) then any description
found next to a $ref
will automatically override any description
found within the schema being dereferenced at that location.
If you want to have finer grained control over looking up references (likely you are looking JSONReference
types up in the Components Object in your code), you may need to do a little work to get the overriding behavior. When case
matching on a reference
JSONSchema.Schema
, you can now pull the CoreContext
out as the second element of the case
and access properties like description
on it. Alternatively, you can call the coreContext
method on JSONSchema
to access the CoreContext
without switching over the cases of its value
. Carry any part or all of this CoreContext
along with the JSONReference
to the location where your code looks the reference up, and then override the properties you want to override.
This may sound a bit inconvenient relative to, say, OpenAPI.Reference
(which handles overriding of description
internally without any extra work on your part). As discussed in the notes on the PR linked to above, there are a few reasons for this design. Perhaps the most undeniable argument for this design is that unlike with OpenAPI reference overriding which only supports description
and summary
, JSON Schema leaves the door open for any properties to live alongside a $ref
and it doesn't explicitly state that overriding should be the behavior when dereferencing and it specifically notes that if you try to perform dereferencing where you handle all possible properties alongside $ref
s then you will almost certainly end up misrepresenting the original author's intent in some cases. Therefore, it is left up to the project using OpenAPIKit to decide which properties to override and which to ignore.
Example
let components = OpenAPI.Components(
schemas: ["test": .string(description: "generic description")]
)
let data = """
{
"type": "object",
"properties": {
"prop1": {
"$ref": "#/components/schemas/test",
"description": "specialized description"
}
}
}
""".data(using: .utf8)!
let schema = try JSONDecoder().decode(JSONSchema.self, from: data)
let property = schema.objectContext?.properties["prop1"]?.value
switch property {
case .reference(let ref, let context):
let result = try components.lookup(ref)
.overriddenNonNil(description: context.description)
XCTAssertEqual(result, .string(description: "specialized description"))
default:
break
}
Breaking Changes
OpenAPIKit module only. Does not apply to OpenAPIKit30 module.
In order to support new versions of the JSON Schema specification that allow $ref
properties to live alongside other annotations like description
, the JSONSchema
type's reference
case had its ReferenceContext
replaced with a full CoreContext
.
Because the ReferenceContext
contained only a required
property and the CoreContext
also has a required
property, some code bases will not need to change at all. However, if you did use the ReferenceContext
by name in your code, you will need to address compiler errors because of this change.
Another way this change may break code is if you have used the JSONSchema
referenceContext
accessor. This accessor has been removed and you can now use the coreContext
accessor on JSONSchema
to get the CoreContext
when it is relevant (which includes reference
cases going forward).
Full Changelog: 3.0.0-beta.1...3.0.0-beta.2
Dynamite
What's Changed
- Fix bug where headers were not allowed to define
explode
when decoding (#301)
Full Changelog: 2.6.0...2.6.1
Names are Forever
In this PR, the process of locally dereferencing a document (i.e. document.locallyDereferenced()
) will also use a new vendor extension to keep track of the Component Object name where any locally dereferenced objects used to be found.
For example, when resolving a JSONReference<Example>
, the resulting Example
will have a vendorExtension
with key x-component-name
and value equal to the name where the newly inlined Example
used to be found in the Components.examples
.
Note that there are three types for which this does not currently happen:
Make an Example of Nothing
What's Changed
- make
value
/externalValue
optional for Example Objects. (#286)
Breaking Changes
The OpenAPI.Example
type's value
property has become optional so you will now need to handle a nil
case or use optional chaining in places where you switch-on or otherwise access that property.
Full Changelog: 3.0.0-alpha.9...3.0.0-beta.1
I Refer You To Your Path
What's Changed
- Fix simplified allOf schema optionality.
- Fix lacking support for Path Item Object references.
This release primarily fixes #280 by allowing Path Items to be references as well as inlined Path Item Objects. This applies to both the OpenAPIKit30
(OpenAPI 3.0.x) and OpenAPIKit
(OpenAPI 3.1.x) modules. However, OpenAPI 3.0.x did not allow Path Item Objects to be stored in the Components Object whereas OpenAPI 3.1.x does, so only external JSON References to Path Item Objects are meaningful when working with OpenAPI 3.0.x.
Noteworthy Differences
OpenAPI.Document
helpers that collect information not stored directly in the document now skip over external JSON References to Path Item Objects. The use of these helpers is the same, but the distinction between internal and external references to Path Item Objects is important here (where before references to Path Item Objects were simply not expressible with OpenAPIKit). These helpers arevar routes: [Route]
,var allOperationIds: [String]
,var allServers: [OpenAPI.Server]
, andvar allTags: Set<String>
.- Because the path to anything in a Document that exists as part of a Path Item Object or its children is now potentially behind a JSON Reference, the error messages for improperly formatted Documents have changed in some cases. They still reflect the same underlying problems, but the verbiage has changed.
- It is now possible to write reference entries to Path Item Objects into the Paths dictionary:
paths: [ "/hello": .reference(.component(named: "path1")) ]
. This internal reference to the Components Object would only be valid for OpenAPI 3.1.x; External references like the following are valid for OpenAPI 3.0.x as well as 3.1.x:paths: [ "/hello": .reference(.external(URL(string: "https://website.com/hi")!)) ]
Breaking Changes
Constructing an entry in the Document.paths
dictionary now requires specifying Either
a JSON Reference to a Path Item Object or the Path Item Object itself -- this means that where you used to write something like:
paths: [
"/hello/world": OpenAPI.PathItem(description: "hi", ...)
]
You will now need to wrap it in an Either
constructor like:
paths: [
"/hello/world": .pathItem(OpenAPI.PathItem(description: "hi", ...))
]
There is also a convenience initializer for Either
in this context which means that you can also write:
paths: [
"/hello/world": .init(description: "hi", ...)
]
You may already have been using the .init
shorthand to construct OpenAPI.PathItem
s in which case your code does not need to change.
Accessing an entry in the Document.paths
dictionary now requires digging into an Either
that may be a JSON Reference or a Path Item Object -- this means that where you used to write something like:
let pathItem = document.paths["hello/world"]
You will now need to decide between the following:
// access the path item (ignoring the possibility that it could be a reference)
let pathItemObject = document.paths["hello/world"]?.pathItemValue
// access the reference directly (ignoring the possibility that it could be a path item object):
let pathItemReference = document.paths["hello/world"]?.reference
// look the path item up in the Components Object (OpenAPIKit module only because this requires OpenAPI 3.1.x):
let pathItem = document.paths["hello/world"].flatMap { document.components[$0] }
// switch on the Either and handle it differently depending on the result:
switch document.paths["hello/world"] {
case .a(let reference):
break
case .b(let pathItem):
break
case nil:
break
}
NOTE: The error you will get in places where you need to make the above adjustments will look like:
Cannot convert value of type 'OpenAPI.PathItem' to expected dictionary value type 'Either<JSONReference<OpenAPI.PathItem>, OpenAPI.PathItem>'
Full Changelog: 3.0.0-alpha.8...3.0.0-alpha.9
All of us need this
Fix a bug with simplification by aligning the required
status of all fragments within an allOf
schema.