Releases: mattpolzin/OpenAPIKit
Required Stability
JSONSchema objects' requiredProperties/optionalProperties are now sorted so that their ordering is stable. These properties are dynamically created from the properties dictionary and therefore the order has never been defined before.
Even now, the order is not publicly guaranteed, but now it will at least be stable which can help with diffing.
U.R.Love
URLs now encode as strings and decode from strings no matter what encoder/decoder you use. This is the treatment already given to URLs by popular encoders and decoders like Foundation's JSON options and Yams's YAML options but now OpenAPIKit takes the liberty of passing URLs to the encoder (and requesting them from the decoder) as strings to make sure that they always get this intuitive treatment.
True Forms
This is a big release that closes two longstanding gaps: An inability to dereference an OpenAPI Document and the lack of any canonical representation of the components of the API described by an OpenAPI Document.
Dereferencing
The OpenAPI specification supports the use of JSON References in a number of places throughout the Document. These references allow authors to reuse one component in multiple places or even just make the route definition section of the document more concise by storing some components in the Components Object.
When traversing an OpenAPI document, these references are often more of an annoyance than anything else; Every time you reach a part of the document where a reference is allowed, you must check whether you are working with a reference or not or maybe even reach out to the Components Object and look a reference up.
This release introduces the OpenAPI.Document locallyDereferenced() method. This method traverses the whole document resolving all references to components found in the Components Object. The result is a document that has replaced many types with dereferenced variants -- anywhere you would have seen Either<JSONReference<Thing>, Thing> you will now just see Thing (or a DereferencedThing, anyway). The dereferenced variants will always expose the properties of the original OpenAPI type.
Before:
let document: OpenAPI.Document = ...
let anOperation: OpenAPI.Operation = document
    .paths["/hello/world"]!
    .get!
let parametersOrReferences = anOperation.parameters
// print the name of all parameters that happen to be inlined:
for parameter in parametersOrReferences.compactMap({ $0.parameterValue }) {
    print(parameter.name)
}
// resolve parameters in order to print the name of them all
for parameter in parametersOrReferences.compactMap(document.components.dereference) {
    print(parameter.name)
}Now:
let document: OpenAPI.Document = ...
let anOperation = try document
    .locallyDereferenced()  // new
    .paths["/hello/world"]!
    .get!
let parameters = anOperation.parameters
// loop over all parameters and print their names
for parameter in parameters {
    print(parameter.name)
}Resolving (to canonical representations)
The OpenAPI Specification leaves numerous opportunities (including JSON References) for authors to write the same documentation in different ways. Sometimes when analyzing an OpenAPI Document or using it to produce something new (a la code generation) you really just need to know what the API looks like, not how the author of the documentation chose to structure the OpenAPI document.
This release introduces the resolved() method on the DereferencedDocument (the result of the locallyDereferenced() method on an OpenAPI.Document). A ResolvedDocument collects information from all over the OpenAPI.Document to form canonical definitions of the routes and endpoints found within. In a resolved document, you work with ResolvedRoute (the canonical counterpart to the OpenAPI.PathItem) and ResolvedEndpoint (the canonical counterpart to the OpenAPI.Operation).
To show the power of a resolved type, let's look at the hypothetical need to look at all parameters for a particular endpoint. To achieve this without resolved types, we need to collect parameters on the Path Item Object and combine them with those on the Operation Object. Even worse, to really get this right we would need to let the parameters of the Operation override those of the Path Item if the parameter names & locations were the same.
Before:
let document: OpenAPI.Document = ...
let aPathItem = try document
    .locallyDereferenced()
    .paths["/hello/world"]!
let anOperation = aPathItem.get!
// going to oversimplify here and not worry
// about collisions between the Path Item and
// Operation parameters.
let parameters = aPathItem.parameters + anOperation.parametersAfter:
let document: OpenAPI.Document = ...
let anEndpoint = try document
    .locallyDereferenced()
    .resolved()  // new
    .routesByPath["/hello/world"]!  // new
    .get!
// no oversimplification here, this is going to get
// us the totally correct comprehensive list of
// parameters for the endpoint.
let parameters = anEndpoint.parametersSchema context accessors and all servers in Document
Additions
- Adds allServersonOpenAPI.Documentto retrieve all servers that are referenced anywhere in the document (whether in the rootserverarray, theserverson a Path Item, or theserverson an Operation.
- Adds accessors that retrieve contexts on JSONSchemas, providing an alternative to destructuring when retrieving an optional context is more convenient.
Bug Fixes
- Breaking: Fixes return type on Components.forceDereference()to be non-optional. It was made optional whenforceDereference()was introduced in v1.2.0 by accident even though it is not possible for that function to produce an optional value. I decided this was an isolated enough breakage to something introduced very recently and therefore am not waiting for a major version to fix the bug.
OpenAPI Document Extensible Validation
Additions
- Add isInternalandisExternalto JSONReference.
- Add forceDereference()methods to OpenAPI.Components to give a throwing alternative to the existingdereference()methods.
- Add validation, as described below.
Validation
It has always been a goal of OpenAPIKit to lean into Swift's type system and make it impossible to represent invalid OpenAPI documents as much as possible. However, there are some things Swift's type system still cannot guarantee. For those things, now there is explicit validation.
Given an OpenAPI.Document, you can call validate() to check the following things (language pulled from the OpenAPI Specification):
- The Responses Object MUST contain at least one response code, and it SHOULD be the response for a successful operation call.
- Each tag name in the list [on the root Document Object] MUST be unique.
- The list [of parameters on a Path Item] MUST NOT include duplicated parameters.
- The list [of parameters on an Operation] MUST NOT include duplicated parameters.
- [Operation Ids] MUST be unique among all operations described in the API.
You can use the validation system to exercise additional control over what a "valid" document looks in your particular use-case. For more information on adding your own validation checks, see the new Validation Documentation.
Expanded Vendor Extension Support
Expand vendor extension (i.e. "specification extension") support to:
- 
OpenAPI.Request
- 
OpenAPI.Response
- 
OpenAPI.SecurityScheme
- 
OpenAPI.Server.Variable
- 
Add routesaccessor onOpenAPI.Documentto retrieve an array of pairings ofPathandPathItem.
Bump Yams version.
Looking over the Yams v3 release, I am inclined to say that v3 of Yams is fully source-compatible with v2 of Yams. There is a noted breaking change of now requiring Swift 4.1+ but OpenAPIKit only supports Swift 5.1+ to begin with.
The upshot of this major version bump is that even though OpenAPIKit only uses Yams for test targets, now downstream packages will not experience dependency conflicts when using OpenAPIKit and trying to use the latest versions of Yams (which include some important bug fixes).
First stable release
Closes #38.
Closes #61.
Closes #64.
As the version number implies, this signals my intention to stop making breaking changes to OpenAPIKit until a v2 release. If you have been playing along so far, I appreciate your patience with the frequent breaking changes throughout the pre-release period.
Additions
- OpenAPISchemaTypeconformances for- URLand- UUID.
- OpenAPI.SecurityScheme.SecurityType.nameexposes a- Stringrepresentable enum value of the name of the security scheme type (oauth2, openIdConnect, http, apiKey).
- OpenAPI.Operation.ResponseOutcomeand the- .responseOutcomesproperty on- Operationexpose an array of response outcomes (structs isomorphic to the key/value pairs of the- Response.Mapfor the- Operation).
- Response.StatusCode.isSuccessto determine if a status code is in the 200 range (including the "2xx" syntax).
- JSONSchema.ObjectContext.optionalPropertiesto pair with the existing spec-mandated- JSONSchema.ObjectContext.requiredProperties.
- Support for discriminators in JSONSchema.
⚠️  Breaking Changes ⚠️ 
- Moves OpenAPI.PathItem.OperationtoOpenAPI.OperationandOpenAPI.PathItem.ParametertoOpenAPI.Parameter.
Nesting these types was both non-essential and also often annoyingly verbose at the call site.
- Renames OpenAPI.Parameter.SchematoOpenAPI.Parameter.SchemaContext.
Parameter.Schema is not a schema but rather a struct containing a schema, among other things. SchemaContext is a better name for this structure.
- Renames OpenAPI.HttpVerbtoOpenAPI.HttpMethodandOpenAPI.PathItem.Endpoint.verbtoOpenAPI.PathItem.Endpoint.method.
"Method" is pretty ubiquitous and even the word the OpenAPI Specification uses. I must have had a bit of writers block when I named it HttpVerb originally.
- Renames OpenAPI.Parameter.schemaOrContent.schemaValuetoOpenAPI.Parameter.schemaOrContent.schemaContextValue.
This goes along with the name change from Parameter.Schema to Parameter.SchemaContext. The callsite makes more sense with this naming and the added .schemaValue that now directly refers to the underlying JSONSchema is more useful.
- 
Changes PathItem.Endpointfrom a tuple to a struct.
- 
JSONSchemagains additional associated values forall(of:),any(of:), andone(of:)to support discriminators.
Fix error reporting on Path decoding
Fixes errors on Path where nested Either decoding errors are involved.
Adding specification extension support
Added specification extensions for:
- Document
- Document.Info
- PathItem
- Components
- Operation
- Server
- Contact
- License
- Parameter
Added Parameter.location to expose a raw representable enum that just represents location (query, header, path, cookie).
- Rename Parameter.LocationtoParameter.Context.
- Rename Parameter.parameterLocationtoParameter.context.