Meet Swift OpenAPI Generator


Swift package plugin to support server API access.  This Dynamic network requests, you need to understand the base, the endpoint and more.

Most services have API documentation, which can be outdated or inaccurate. You can use inspection – but that provides incomplete understanding.

Using formal, structured specification can help reduce these challenges and ambiguities.  This session addresses how apple and swift are support OpenAPI specifications to improve APIs with server apps.

Exploring OpenAPI

  • You can use either YAML or JSON to document the server behavior.  There are tools for testing and generating interactive documentation and spec driven development.
  • There is a lot of boilerplate code you have to write in swift to deal with APIs. So by using OpenAPI you can use tooling to generate most of the boiler plate code.  Here’s a trivial example
  • If we add one optional parameter sec an see that integrated in the Yaml for the Get 
  • The generated code is generated a run time so it is always in sync with the API specification 

Making API calls from your app

  • Sample app is update to replace the sample app to generate one of the cat emoji
  • Here’s the API Specification 
  • The entirety of the code for the API is seen here. Package dependencies are available in the session notes
  • You must configure the generator plugin via the a YAML file
  • Once all the setup is done.. here’s the code:
import SwiftUI
import OpenAPIRuntime
import OpenAPIURLSession

#Preview {
    ContentView()
}

struct ContentView: View {
    @State private var emoji = "🫥"

    var body: some View {
        VStack {
            Text(emoji).font(.system(size: 100))
            Button("Get cat!") {
                Task { try? await updateEmoji() }
            }
        }
        .padding()
        .buttonStyle(.borderedProminent)
    }

    let client: Client

    init() {
        self.client = Client(
            serverURL: try! Servers.server1(),
            transport: URLSessionTransport()
        )
    }

    func updateEmoji() async throws {
        let response = try await client.getEmoji(Operations.getEmoji.Input())

        switch response {
        case let .ok(okResponse):
            switch okResponse.body {
            case .text(let text):
                emoji = text
            }
        case .undocumented(statusCode: let statusCode, _):
            print("cat-astrophe: \(statusCode)")
            emoji = "🙉"
        }
    }
}
  • Pretty simple, huh?

Adapting as the API evolves

  • As the API evolves, you can address the new versions based on app changes based on the new YAML file
  • Adding parameters are also easy to change in your code

Testing your app with mocks

  • Creating a Mock is needed to testing
  • By creating an APIProtocol{} struct you can now mock your code, and make your view generic to utilize the protocol  – this allows for running without a server.  Check out the code at https://developer.apple.com/wwdc23/10171 

Sever development in Swift

  • There is an example of a swift console App to run on the machine.  Using the API Generator simplified the server code requiremnts so you can just focus on the business logic.
  • The demo is using Vapor for the server code
  • The usage of Spec Driven development allows you to focus on your business logic on the server and the OpenAPI generator will automatically generate the stubs for you
  • OpenAPI Generator is a open source project available on GitHub https://github.com/apple/swift-openapi-generator