dankinsoid/SwiftOpenAPI
Swift library which can generate output compatible with OpenAPI 3.1.0
Description
SwiftOpenAPI is a Swift library which can generate output compatible with OpenAPI version 3.1.0. You can describe your API using OpenAPIObject type.\ The main accent in the library is on simplifying the syntax: the active use of literals (array, dictionary, string etc) and static methods greatly simplifies writing and reading OpenAPI docs in Swift.
Short example
try OpenAPIObject(
openapi: "3.0.11",
info: InfoObject(
title: "Example API",
version: "0.1.0"
),
servers: [
"https://example-server.com",
"https://example-server-test.com"
],
paths: [
"services": .get(
summary: "Get services",
OperationObject(description: "Get services")
),
"login": .post(
OperationObject(
description: "login",
requestBody: .ref(components: \.requestBodies, "LoginRequest"),
responses: [
.ok: .ref(components: \.responses, "LoginResponse"),
.unauthorized: .ref(components: \.responses, "ErrorResponse")
]
)
),
"/services/{serviceID}": [
.get: OperationObject(description: "Get service"),
.delete: OperationObject(description: "Delete service")
],
"/services": .ref(components: \.pathItems, "T")
],
components: ComponentsObject(
schemas: [
"LoginBody": [
"username": .string,
"password": .string
],
"LoginResponse": .value(.encode(LoginResponse.example))
],
examples: [
"LoginBody": [
"username": "SomeUser",
"password": "12345678"
],
"LoginResponse": .value(
ExampleObject(value: .encode(LoginResponse.example))
)
],
requestBodies: [
"LoginRequest": .value(
RequestBodyObject(
content: [
.application(.json): MediaTypeObject(
schema: .ref(components: \.schemas, "LoginBody")
)
],
required: nil
)
)
]
)
)Pets store example
PetsSwagger.swift demonstrates syntaxis well
Creating schemas and parameters for `Codable` types
There is a possibility to create SchemeObject, [ParameterObject], AnyValue and [String: HeaderObject] instances from Codable types. It's possible to use SchemeObject.decode/encode, [ParameterObject].decode/encode, [String: HeaderObject].decode/encode and AnyValue.encode methods for it.
let loginBodySchemeFromType: SchemeObject = try .decode(LoginBody.self)
let loginBodySchemeFromInstance: SchemeObject = try .encode(LoginBody.example)
let loginBodyExample = try ExampleObject(value: .encode(LoginBody.example))You can customize the encoding/decoding result by implementing OpenAPIDescriptable and OpenAPIType protocols.
OpenAPIDescriptableprotocol allows you to provide a custom description for the type and its properties.@OpenAPIAutoDescriptablemacro implements this protocol with your comments.
import SwiftOpenAPI
@OpenAPIDescriptable
/// Login request body.
struct LoginBody: Codable {
/// Username string.
let username: String
/// Password string. Encoded.
let password: String
}Manually:
struct LoginBody: Codable, OpenAPIDescriptable {
let username: String
let password: String
static var openAPIDescription: OpenAPIDescriptionType? {
OpenAPIDescription<CodingKeys>("Login request body.")
.add(for: .username, "Username string.")
.add(for: .password, "Password string. Encoded.")
}
}OpenAPITypeprotocol allows you to provide a custom schema for the type.
struct Color: Codable, OpenAPIType {
static var openAPISchema: SchemaObject {
.string(format: "hex", description: "Color in hex format")
}
}Specification extensions
While the OpenAPI Specification tries to accommodate most use cases, additional data can be added to extend the specification at certain points.\
var api = OpenAPIObject(...)
api.specificationExtensions = ["x-some-extension": "some value"]
// or
api.specificationExtensions = try? SpecificationExtensions(from: someEncodable)It was a bit tricky challenge to implement additional dynamic properties for any codable struct. The solution is to use SpecificationExtendable protocol in combination with WithSpecExtensions property wrapper. There is two ways to decode/encode SpecificationExtendable types with additional properties:
- Use
SpecificationExtendable.json,SpecificationExtendable.Type.from(json:)methods.
let schema = try SchemaObject.from(json: jsonData)
let jsonData = try schema.json()- If you cannot use custom decoding methods, you can use
WithSpecExtensionswrapper.
let api = try WithSpecExtensions(wrappedValue: OpenAPIObject(...))
let jsonData = try JSONEncoder().encode(api)TODO
URItype instead ofStringrefactormethod onOpenAPIObject(?)- Extend
RuntimeExpressiontype DataEncodingFormat
Installation
Create a Package.swift file.
// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "SomeProject",
dependencies: [
.package(url: "https://github.com/dankinsoid/SwiftOpenAPI.git", from: "2.23.0")
],
targets: [
.target(name: "SomeProject", dependencies: ["SwiftOpenAPI"])
]
)$ swift buildLicense
SwiftOpenAPI is available under the MIT license. See the LICENSE file for more info.
Package Metadata
Repository: dankinsoid/SwiftOpenAPI
Stars: 12
Forks: 9
Open issues: 0
Default branch: main
Primary language: swift
License: MIT
Topics: openapi, swift
README: README.md