diff --git a/Sources/_OpenAPIGeneratorCore/Translator/ServerTranslator/ServerTranslator.swift b/Sources/_OpenAPIGeneratorCore/Translator/ServerTranslator/ServerTranslator.swift index 2f636608..b6289962 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/ServerTranslator/ServerTranslator.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/ServerTranslator/ServerTranslator.swift @@ -39,22 +39,67 @@ struct ServerFileTranslator: FileTranslator { + config.additionalImports .map { ImportDescription(moduleName: $0) } - let allOperations = try OperationDescription + let allOperations = + try OperationDescription .all( from: doc.paths, in: components, asSwiftSafeName: swiftSafeName ) + let (registerHandlersDecl, serverMethodDecls) = try translateRegisterHandlers(allOperations) + + let protocolExtensionDecl: Declaration = .extension( + accessModifier: nil, + onType: Constants.APIProtocol.typeName, + declarations: [ + registerHandlersDecl + ] + ) + + let serverExtensionDecl: Declaration = .extension( + accessModifier: .fileprivate, + onType: Constants.Server.Universal.typeName, + whereClause: .init(requirements: [ + .conformance( + Constants.Server.Universal.apiHandlerName, + Constants.APIProtocol.typeName + ) + ]), + declarations: serverMethodDecls + ) + + return StructuredSwiftRepresentation( + file: .init( + name: GeneratorMode.server.outputFileName, + contents: .init( + topComment: topComment, + imports: imports, + codeBlocks: [ + .declaration(protocolExtensionDecl), + .declaration(serverExtensionDecl), + ] + ) + ) + ) + } + + /// Returns a declaration of the registerHandlers method and + /// the declarations of the individual operation methods. + /// - Parameter operations: The operations found in the OpenAPI document. + func translateRegisterHandlers( + _ operations: [OperationDescription] + ) throws -> (Declaration, [Declaration]) { var registerHandlersDeclBody: [CodeBlock] = [] - let serverMethodDeclPairs = try allOperations + let serverMethodDeclPairs = + try operations .map { operation in try translateServerMethod(operation, serverUrlVariableName: "server") } let serverMethodDecls = serverMethodDeclPairs.map(\.functionDecl) // To avoid an used variable warning, we add the server variable declaration - // and server method register cals to the body of the register handler declaration + // and server method register calls to the body of the register handler declaration // only when there is at least one registration call. if !serverMethodDeclPairs.isEmpty { let serverMethodRegisterCalls = serverMethodDeclPairs.map(\.registerCall) @@ -117,39 +162,6 @@ struct ServerFileTranslator: FileTranslator { body: registerHandlersDeclBody ) ) - - let protocolExtensionDecl: Declaration = .extension( - accessModifier: nil, - onType: Constants.APIProtocol.typeName, - declarations: [ - registerHandlersDecl - ] - ) - - let serverExtensionDecl: Declaration = .extension( - accessModifier: .fileprivate, - onType: Constants.Server.Universal.typeName, - whereClause: .init(requirements: [ - .conformance( - Constants.Server.Universal.apiHandlerName, - Constants.APIProtocol.typeName - ) - ]), - declarations: serverMethodDecls - ) - - return StructuredSwiftRepresentation( - file: .init( - name: GeneratorMode.server.outputFileName, - contents: .init( - topComment: topComment, - imports: imports, - codeBlocks: [ - .declaration(protocolExtensionDecl), - .declaration(serverExtensionDecl), - ] - ) - ) - ) + return (registerHandlersDecl, serverMethodDecls) } } diff --git a/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift b/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift index df663230..bcc7e95a 100644 --- a/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift +++ b/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift @@ -1185,6 +1185,44 @@ final class SnippetBasedReferenceTests: XCTestCase { ) } + func testServerRegisterHandlers_oneOperation() throws { + try self.assertServerRegisterHandlers( + """ + /health: + get: + operationId: getHealth + responses: + '200': + description: A success response with a greeting. + content: + text/plain: + schema: + type: string + """, + """ + public func registerHandlers( + on transport: any ServerTransport, + serverURL: URL = .defaultOpenAPIServerURL, + configuration: Configuration = .init(), + middlewares: [any ServerMiddleware] = [] + ) throws { + let server = UniversalServer( + serverURL: serverURL, + handler: self, + configuration: configuration, + middlewares: middlewares + ) + try transport.register( + { try await server.getHealth(request: $0, metadata: $1) }, + method: .get, + path: server.apiPathComponentsWithServerPrefix(["health"]), + queryItemNames: [] + ) + } + """ + ) + } + func testPathWithPathItemReference() throws { XCTAssertThrowsError( try self.assertPathsTranslation( @@ -1595,6 +1633,23 @@ extension SnippetBasedReferenceTests { let translation = try translator.translateAPIProtocol(paths) try XCTAssertSwiftEquivalent(translation, expectedSwift, file: file, line: line) } + + func assertServerRegisterHandlers( + _ pathsYAML: String, + _ expectedSwift: String, + file: StaticString = #filePath, + line: UInt = #line + ) throws { + let (_, _, translator) = try makeTranslators() + let paths = try YAMLDecoder().decode(OpenAPI.PathItem.Map.self, from: pathsYAML) + let operations = try OperationDescription.all( + from: paths, + in: .noComponents, + asSwiftSafeName: translator.swiftSafeName + ) + let (registerHandlersDecl, _) = try translator.translateRegisterHandlers(operations) + try XCTAssertSwiftEquivalent(registerHandlersDecl, expectedSwift, file: file, line: line) + } } private func XCTAssertEqualWithDiff(