Skip to content

colemancda/OpenAPIKit

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MIT license Swift 5.1 Build Status

OpenAPIKit

⚠️ This repository was recently renamed mattpolzin/OpenAPIKit in order to align the repository and package names. For now, GitHub appears to be redirecting mattpolzin/OpenAPI to the new location, but I recommend updating your package configurations anyway.

A library containing Swift types that encode to- and decode from OpenAPI Documents and their components.

Usage

Decoding OpenAPI Documents

You can decode a JSON OpenAPI document (i.e. using the JSONDecoder from Foundation library) or a YAML OpenAPI document (i.e. using the YAMLDecoder from the Yams library) with the following code:

let decoder = ... // JSONDecoder() or YAMLDecoder()
let openAPIDoc = try decoder.decode(OpenAPI.Document, from: ...)

Encoding OpenAPI Documents

You can encode a JSON OpenAPI document (i.e. using the JSONEncoder from the Foundation library) or a YAML OpenAPI document (i.e. using the YAMLEncoder from the Yams library) with the following code:

let openAPIDoc = ...
let encoder = ... // JSONEncoder() or YAMLEncoder()
let encodedOpenAPIDoc = try encoder.encode(openAPIDoc)

Generating OpenAPI Documents

See VaporOpenAPI / VaporOpenAPIExample for an example of generating OpenAPI from a Vapor application's routes.

See JSONAPI+OpenAPI for an example of generating OpenAPI response schemas from JSON:API response documents.

OpenAPI Document structure

The types used by this library largely mirror the object definitions found in the OpenAPI specification version 3.0.2. The Project Status lists each object defined by the spec and the name of the respective type in this library.

Document Root

At the root there is an OpenAPI.Document. In addition to some information that applies to the entire API, the document contains OpenAPI.Components (essentially a dictionary of reusable components that can be referenced with JSONReferences) and an OpenAPI.PathItem.Map (a dictionary of routes your API defines).

Routes

Each route is an entry in the document's OpenAPI.PathItem.Map. The keys of this dictionary are the paths for each route (i.e. /widgets). The values of this dictionary are OpenAPI.PathItems which define any combination of endpoints (i.e. GET, POST, PATCH, etc.) that the given route supports.

Endpoints

Each endpoint on a route is defined by an OpenAPI.PathItem.Operation. Among other things, this operation can specify the parameters (path, query, header, etc.), request body, and response bodies/codes supported by the given endpoint.

Request/Response Bodies

Request and response bodies can be defined in great detail using OpenAPI's derivative of the JSON Schema specification. This library uses the JSONSchema type for such schema definitions.

Schemas

Fundamental types are specified as JSONSchema.integer, JSONSchema.string, JSONSchema.boolean, etc.

Properties are given as arguments to static constructors. By default, types are non-nullable, required, and generic.

A type can be made optional (i.e. it can be omitted) with JSONSchema.integer(required: false) or JSONSchema.integer.optionalSchemaObject(). A type can be made nullable with JSONSchema.number(nullable: true) or JSONSchema.number.nullableSchemaObject().

A type's format can be further specified, for example JSONSchema.number(format: .double) or JSONSchema.string(format: .dateTime).

You can specify a schema's allowed values (e.g. for an enumerated type) with JSONSchema.string(allowedValues: "hello", "world").

Each type has its own additional set of properties that can be specified. For example, integers can have a minimum value: JSONSchema.integer(minimum: (0, exclusive: true)) (where exclusive means the number must be greater than 0, not greater-than-or-equal-to 0).

Compound objects can be built with JSONSchema.array, JSONSchema.object, JSONSchema.all(of:), etc.

For example, perhaps a person is represented by the schema:

JSONSchema.object(
  title: "Person",
  properties: [
    "first_name": .string(minLength: 2),
    "last_name": .string(nullable: true),
    "age": .integer,
    "favorite_color": .string(allowedValues: "red", "green", "blue")
  ]
)
Generating Schemas

Some schemas can be easily generated from Swift types. Many of the fundamental Swift types support schema representations out-of-box.

For example, the following are true

String.openAPINode() == JSONSchema.string

Bool.openAPINode() == JSONSchema.boolean

Double.openAPINode() == JSONSchema.number(format: .double)

Float.openAPINode() == JSONSchema.number(format: .float)
...

Array and Optional are supported out-of-box. For example, the following are true

[String].openAPINode() == .array(items: .string)

[Int].openAPINode() == .array(items: .integer)

Int32?.openAPINode() == .integer(format: .int32, required: false)

[String?].openAPINode() == .array(items: .string(required: false))
...
AnyCodable

A subset of supported Swift types require a JSONEncoder either to make an educated guess at the JSONSchema for the type or in order to turn arbitrary types into AnyCodable for use as schema examples or allowed values.

Swift enums produce schemas with allowed values specified as long as they conform to CaseIterable, Encodable, and AnyJSONCaseIterable (the last of which is free given the former two).

enum CodableEnum: String, CaseIterable, AnyJSONCaseIterable, Codable {
    case one
    case two
}

let schema = CodableEnum.caseIterableOpenAPISchemaGuess(using: JSONEncoder())
// ^ equivalent, although not equatable, to:
let sameSchema = JSONSchema.string(
  allowedValues: "one", "two"
)

Swift structs produce a best-guess schema as long as they conform to Sampleable and Encodable

struct Nested: Encodable, Sampleable {
  let string: String
  let array: [Int]

  // `Sampleable` just enables mirroring, although you could use it to produce
  // OpenAPI examples as well.
  static let sample: Self = .init(
    string: "",
    array: []
  )
}

let schema = Nested.genericOpenAPISchemaGuess(using: JSONEncoder())
// ^ equivalent and indeed equatable to:
let sameSchema = JSONSchema.object(
  properties: [
    "string": .string,
    "array": .array(items: .integer)
  ]
)

Notes

This library does not currently support file reading at all muchless following $refs to other files and loading them in.

This library is opinionated about a few defaults when you use the Swift types, however encoding and decoding stays true to the spec. Some key things to note:

  1. Within schemas, required is specified on the property rather than being specified on the parent object (encoding/decoding still follows the OpenAPI spec).
    • ex JSONSchema.object(properties: [ "val": .string(required: true)]) is an "object" type with a required "string" type property.
  2. Within schemas, required defaults to true on initialization (again, encoding/decoding still follows the OpenAPI spec).
    • ex. JSONSchema.string is a required "string" type.
    • ex. JSONSchema.string(required: false) is an optional "string" type.

Project Status

OpenAPI Object (OpenAPI.Document)

  • openapi (openAPIVersion)
  • info
  • servers
  • paths
  • components
  • security
  • tags
  • externalDocs

Info Object (OpenAPI.Document.Info)

  • title
  • description
  • termsOfService
  • contact
  • license
  • version

Contact Object (OpenAPI.Document.Info.Contact)

  • name
  • url
  • email

License Object (OpenAPI.Document.Info.License)

  • name
  • url

Server Object (OpenAPI.Server)

  • url
  • description
  • variables

Server Variable Object (OpenAPI.Server.Variable)

  • enum
  • default
  • description

Components Object (OpenAPI.Components)

  • schemas
  • responses
  • parameters
  • examples
  • requestBodies
  • headers
  • securitySchemes
  • links
  • callbacks

Paths Object (OpenAPI.PathItem.Map)

  • dictionary

Path Item Object (OpenAPI.PathItem)

  • summary
  • description
  • servers
  • parameters
  • get
  • put
  • post
  • delete
  • options
  • head
  • patch
  • trace

Operation Object (OpenAPI.PathItem.Operation)

  • tags
  • summary
  • description
  • externalDocs
  • operationId
  • parameters
  • requestBody
  • responses
  • callbacks
  • deprecated
  • security
  • servers

External Document Object (OpenAPI.ExternalDoc)

  • description
  • url

Parameter Object (OpenAPI.PathItem.Parameter)

  • name
  • in (parameterLocation)
  • description
  • required (part of parameterLocation)
  • deprecated
  • allowEmptyValue (part of parameterLocation)
  • content (schemaOrContent)
  • schema (schemaOrContent)
    • style
    • explode
    • allowReserved
    • example
    • examples

Request Body Object (OpenAPI.Request)

  • description
  • content
  • required

Media Type Object (OpenAPI.Content)

  • schema
  • example
  • examples
  • encoding
  • specification extensions (vendorExtensions)

Encoding Object (OpenAPI.Content.Encoding)

  • contentType
  • headers
  • style
  • explode
  • allowReserved

Responses Object (OpenAPI.Response.Map)

  • dictionary

Response Object (OpenAPI.Response)

  • description
  • headers
  • content
  • links

Callback Object

  • {expression}

Example Object (OpenAPI.Example)

  • summary
  • description
  • value
  • externalValue (part of value)
  • specification extensions (vendorExtensions)

Link Object

  • operationRef
  • operationId
  • parameters
  • requestBody
  • description
  • server

Header Object (OpenAPI.Header)

  • description
  • required
  • deprecated
  • content
  • schema
    • style
    • explode
    • allowReserved
    • example
    • examples

Tag Object (OpenAPI.Tag)

  • name
  • description
  • externalDocs

Reference Object (JSONReference)

  • $ref
    • local (same file) reference (node case)
      • encode
      • decode
      • dereference
    • remote (different file) reference (file case)
      • encode
      • decode
      • dereference

Schema Object (JSONSchema)

  • Mostly complete support for JSON Schema inherited keywords
  • Specification Extensions
  • nullable
  • discriminator
  • readOnly
  • writeOnly
  • xml
  • externalDocs
  • example
  • deprecated

Discriminator Object (OpenAPI.Discriminator)

  • propertyName
  • mapping

XML Object (OpenAPI.XML)

  • name
  • namespace
  • prefix
  • attribute
  • wrapped

Security Scheme Object (OpenAPI.SecurityScheme)

  • type
  • description
  • name (SecurityType .apiKey case)
  • in (location in SecurityType .apiKey case)
  • scheme (SecurityType .http case)
  • bearerFormat (SecurityType .http case)
  • flows
  • openIdConnectUrl (SecurityType .openIdConnect case)

OAuth Flows Object

  • implicit
  • password
  • clientCredentials
  • authorizationCode

OAuth Flow Object

  • authorizationUrl
  • tokenUrl
  • refreshUrl
  • scopes

Security Requirement Object (OpenAPI.Document.SecurityRequirement)

  • {name} (using JSONReferences instead of a stringy API)

About

Swift OpenAPI Building

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 100.0%