Skip to content

Releases: mattpolzin/OpenAPIKit

Noted (release candidate)

20 Sep 03:34
0ee7ed4
Compare
Choose a tag to compare
Pre-release

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

13 Sep 03:06
beca680
Compare
Choose a tag to compare
Inline Skates Pre-release
Pre-release

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).
  • Links and CallbacksMaps are now dereferenced when calling the dereferenced(in:) and locallyDereferenced() methods.
  • JSON Schemas now support const (which is decoded as a single entry in the JSONSchema type's CoreContext's allowedValues array). (only OpenAPIKit, not OpenAPIKit30).

Breaking Changes

  1. JSONSchema's initializers no longer take vendorExtensions; instead, use the .with(vendorExtensions:) function to add vendor extensions to a schema or build the vendor extensions into the schema's CoreContext to begin with. (only OpenAPIKit module, not OpenAPIKit30).
  2. The DereferencedOperation type's callbacks property is now an OpenAPI.DereferencedCallbacksMap instead of an OpenAPI.CallbacksMap.
  3. The DereferencedResponse type's links property is now an OrderedDictionary<String, OpenAPI.Link> instead of an OpenAPI.Link.Map.
  4. When a JSONSchema only has one allowedValue, it will now be encoded as const rather than enum. (only OpenAPIKit module, not OpenAPIKit30).
  5. The JSONSchema type's coreContext accessor now gives a non-optional value because all cases have a CoreContext. (only OpenAPIKit module, not OpenAPIKit30).

Full Changelog: 3.0.0-beta.4...3.0.0-beta.5

Flexibility is Key

05 Sep 00:32
0cdd48c
Compare
Choose a tag to compare
Flexibility is Key Pre-release
Pre-release

What's Changed

  • Optional responses within operations (#303)
  • Add core context for null schemas (#305)
  • Optional paths within documents (#275)

New Contributors

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.

  1. 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)).
  2. The null case of JSONSchema.Value now has a CoreContext 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).
  3. The JSONSchema.null property that used to serve as a convenient way of creating a null-type JSONSchema 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

30 Aug 14:59
ccdcb64
Compare
Choose a tag to compare
Pre-release

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)

26 Aug 23:27
c598406
Compare
Choose a tag to compare
Dynamite (3) Pre-release
Pre-release

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 $refs

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 $refs 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

26 Aug 22:02
0f712cc
Compare
Choose a tag to compare

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

21 Aug 04:44
e9c50c9
Compare
Choose a tag to compare

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:

  1. JSONSchema does not yet support vendorExtensions so this feature does not yet apply there (#292).
  2. Link does not get dereferenced yet so this feature does not yet apply there (#293).
  3. Callback does not get dereferenced yet so this feature does not yet apply there (#294).

Make an Example of Nothing

19 Aug 04:44
faced11
Compare
Choose a tag to compare
Pre-release

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

26 Jul 03:42
e805233
Compare
Choose a tag to compare
Pre-release

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 are var routes: [Route], var allOperationIds: [String], var allServers: [OpenAPI.Server], and var 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.PathItems 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

19 Jul 23:36
7e3969e
Compare
Choose a tag to compare

Fix a bug with simplification by aligning the required status of all fragments within an allOf schema.