Recognizing APIProtocol from a Different Target

Hello, I'm currently practicing server configuration using swift-openapi-generator and Vapor. As seen in the WWDC24 session "Explore the Swift on Server ecosystem", I'm working with two separate targets. However, I'm facing difficulties in recognizing the APIProtocol, which is specified in the openapi.yaml file of the target containing the openapi-generator, from the executable target. The project structure matches the one shown in the WWDC24 session:

├── Package.resolved
├── Package.swift
└── Sources
    ├── EventAPI
    │   ├── EventAPI.swift  // This file is empty.
    │   ├── openapi-generator-config.yaml
    │   └── openapi.yaml
    └── EventService
        └── Service.swift

The Package.swift file is structured as follows:

// swift-tools-version: 5.10
import PackageDescription

let package = Package(
  name: "EventService",
  platforms: [.macOS(.v14)],
  dependencies: [
    .package(url: "https://github.com/vapor/vapor.git", from: "4.99.3"),
    .package(url: "https://github.com/apple/swift-openapi-generator", from: "1.2.1"),
    .package(url: "https://github.com/apple/swift-openapi-runtime", from: "1.4.0"),
    .package(url: "https://github.com/swift-server/swift-openapi-vapor", from: "1.0.1"),
  ],
  targets: [
    .target(
      name: "EventAPI",
      dependencies: [
        .product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
      ],
      plugins: [
        .plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator"),
      ]
    ),
    .executableTarget(
      name: "EventService",
      dependencies: [
        "EventAPI",
        .product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
        .product(name: "OpenAPIVapor", package: "swift-openapi-vapor"),
        .product(name: "Vapor", package: "vapor"),
      ]
    ),
  ]
)

The EventService code is as follows:

import OpenAPIRuntime
import OpenAPIVapor
import Vapor
import EventAPI

@main
struct EventService {
  static func main() async throws {
    let application = try await Vapor.Application.make()
    let transport = VaporTransport(routesBuilder: application)

    let service = EventService()
    try service.registerHandlers(on: transport, serverURL: URL(string: "/v1")!) // Value of type 'EventService' has no member 'registerHandlers'
    try await application.execute()
  }
}

extension EventService: APIProtocol { // Cannot find type 'APIProtocol' in scope

}

I'm wondering if I'm missing something to resolve this issue.
If there's a correct way to approach this, I would greatly appreciate your advice.
Thank you.

Can you share the contents of openapi-generator-config.yaml?

2 Likes

The openapi-generator-config.yaml file is written as follows:

generate:
  - types
  - server

I have uploaded the code I wrote to the following repository. If there are any mistakes or issues, could you please let me know? You can find the code at GitHub - WhiteHyun/OpenAPI-Vapor-Server.

Right, you need to add accessModifier: package or public. It's internal by default.

1 Like

That's quite interesting! I had posted the question because the code wasn't working even after setting the accessModifier, but now when I try it again, it seems to be functioning properly. Maybe I was possessed by a demon or something, haha.
Thank you for your help, @Honza_Dvorsky!

2 Likes

I suspect it did work, live issues in Xcode just sometimes take longer to update when the symbols are coming from files generated by a build plugin.

Glad it's working now!

4 Likes