diff --git a/Package.swift b/Package.swift index ca35c463..5e6f07e0 100644 --- a/Package.swift +++ b/Package.swift @@ -80,7 +80,7 @@ let package = Package( // Tests-only: Runtime library linked by generated code, and also // helps keep the runtime library new enough to work with the generated // code. - .package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from: "0.1.10")), + .package(url: "https://github.com/apple/swift-openapi-runtime", .upToNextMinor(from: "0.1.11")), // Build and preview docs .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), diff --git a/Sources/_OpenAPIGeneratorCore/Extensions/SwiftFormat.swift b/Sources/_OpenAPIGeneratorCore/Extensions/SwiftFormat.swift index b4e4a6ad..e2672c0f 100644 --- a/Sources/_OpenAPIGeneratorCore/Extensions/SwiftFormat.swift +++ b/Sources/_OpenAPIGeneratorCore/Extensions/SwiftFormat.swift @@ -32,6 +32,7 @@ extension String { configuration.lineBreakAroundMultilineExpressionChainComponents = true configuration.indentConditionalCompilationBlocks = false configuration.maximumBlankLines = 0 + configuration.lineLength = 120 let formatter = SwiftFormatter(configuration: configuration) try formatter.format( source: self, diff --git a/Sources/_OpenAPIGeneratorCore/Translator/ClientTranslator/translateClientMethod.swift b/Sources/_OpenAPIGeneratorCore/Translator/ClientTranslator/translateClientMethod.swift index 0d3fcf5d..b40c3b0c 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/ClientTranslator/translateClientMethod.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/ClientTranslator/translateClientMethod.swift @@ -30,7 +30,7 @@ extension ClientFileTranslator { left: "path", right: .try( .identifier("converter") - .dot("renderedRequestPath") + .dot("renderedPath") .call([ .init(label: "template", expression: .literal(pathTemplate)), .init(label: "parameters", expression: pathParamsArrayExpr), diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift index 13a4f286..71cd23fa 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTranslations/translateStringEnum.swift @@ -48,10 +48,12 @@ extension FileTranslator { let generateUnknownCases = shouldGenerateUndocumentedCaseForEnumsAndOneOfs let baseConformance = generateUnknownCases ? Constants.StringEnum.baseConformanceOpen : Constants.StringEnum.baseConformanceClosed + let conformances = + generateUnknownCases ? Constants.StringEnum.conformancesOpen : Constants.StringEnum.conformancesClosed let unknownCaseName = generateUnknownCases ? Constants.StringEnum.undocumentedCaseName : nil return try translateRawRepresentableEnum( typeName: typeName, - conformances: [baseConformance] + Constants.StringEnum.conformances, + conformances: [baseConformance] + conformances, userDescription: userDescription, cases: cases, unknownCaseName: unknownCaseName, diff --git a/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/Constants.swift b/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/Constants.swift index 695d9af1..9ecc281a 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/Constants.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/CommonTypes/Constants.swift @@ -151,13 +151,19 @@ enum Constants { static let baseConformanceClosed: String = "String" /// The types that every enum conforms to. - static let conformances: [String] = [ + static let conformancesOpen: [String] = [ "Codable", "Hashable", "Sendable", - "_AutoLosslessStringConvertible", "CaseIterable", ] + + /// The types that every enum conforms to. + static let conformancesClosed: [String] = [ + "Codable", + "Hashable", + "Sendable", + ] } /// Constants related to generated oneOf enums. @@ -370,8 +376,11 @@ enum Constants { /// The substring used in method names for the JSON coding strategy. static let json: String = "JSON" - /// The substring used in method names for the text coding strategy. - static let text: String = "Text" + /// The substring used in method names for the URI coding strategy. + static let uri: String = "URI" + + /// The substring used in method names for the string coding strategy. + static let string: String = "String" /// The substring used in method names for the binary coding strategy. static let binary: String = "Binary" diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Content/CodingStrategy.swift b/Sources/_OpenAPIGeneratorCore/Translator/Content/CodingStrategy.swift index 2cea6bcb..b36b000d 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Content/CodingStrategy.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Content/CodingStrategy.swift @@ -18,8 +18,11 @@ enum CodingStrategy: String, Hashable, Sendable { /// A strategy using JSONEncoder/JSONDecoder. case json - /// A strategy using LosslessStringConvertible. - case text + /// A strategy using URIEncoder/URIDecoder. + case uri + + /// A strategy using StringEncoder/StringDecoder. + case string /// A strategy that passes through the data unmodified. case binary @@ -29,8 +32,10 @@ enum CodingStrategy: String, Hashable, Sendable { switch self { case .json: return Constants.CodingStrategy.json - case .text: - return Constants.CodingStrategy.text + case .uri: + return Constants.CodingStrategy.uri + case .string: + return Constants.CodingStrategy.string case .binary: return Constants.CodingStrategy.binary } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift index 8ed19037..497360fc 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentInspector.swift @@ -203,7 +203,7 @@ extension FileTranslator { { diagnostics.emitUnsupportedIfNotNil( chosenContent.1.encoding, - "Custom encoding for JSON content", + "Custom encoding for multipart/formEncoded content", foundIn: "\(foundIn), content \(contentType.originallyCasedTypeAndSubtype)" ) } @@ -234,11 +234,15 @@ extension FileTranslator { ) -> SchemaContent? { if contentKey.isJSON { let contentType = ContentType(contentKey.typeAndSubtype) - diagnostics.emitUnsupportedIfNotNil( - contentValue.encoding, - "Custom encoding for JSON content", - foundIn: "\(foundIn), content \(contentKey.rawValue)" - ) + if contentType.lowercasedType == "multipart" + || contentType.lowercasedTypeAndSubtype.contains("application/x-www-form-urlencoded") + { + diagnostics.emitUnsupportedIfNotNil( + contentValue.encoding, + "Custom encoding for multipart/formEncoded content", + foundIn: "\(foundIn), content \(contentType.originallyCasedTypeAndSubtype)" + ) + } return .init( contentType: contentType, schema: contentValue.schema diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentType.swift b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentType.swift index 991f9135..83c0a149 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentType.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Content/ContentType.swift @@ -70,7 +70,7 @@ struct ContentType: Hashable { case .json: return .json case .text: - return .text + return .string case .binary: return .binary } diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift index 46e63d5a..ee75bb73 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/TypedParameter.swift @@ -158,23 +158,23 @@ extension FileTranslator { schema = schemaContext.schema style = schemaContext.style explode = schemaContext.explode - codingStrategy = .text + codingStrategy = .uri // Check supported exploded/style types let location = parameter.location switch location { case .query: - guard case .form = schemaContext.style else { + guard case .form = style else { diagnostics.emitUnsupported( - "Non-form style query params", + "Query params of style \(style.rawValue), explode: \(explode)", foundIn: foundIn ) return nil } case .header, .path: - guard case .simple = schemaContext.style else { + guard case .simple = style else { diagnostics.emitUnsupported( - "Non-simple style \(location.rawValue) params", + "\(location.rawValue) params of style \(style.rawValue), explode: \(explode)", foundIn: foundIn ) return nil diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift index fe880797..dfef7582 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Parameters/translateParameter.swift @@ -207,7 +207,7 @@ extension ServerFileTranslator { convertExpr = .try( .identifier("converter").dot(methodName("QueryItem")) .call([ - .init(label: "in", expression: .identifier("metadata").dot("queryParameters")), + .init(label: "in", expression: .identifier("request").dot("query")), .init(label: "style", expression: .dot(typedParameter.style.runtimeName)), .init(label: "explode", expression: .literal(.bool(typedParameter.explode))), .init(label: "name", expression: .literal(parameter.name)), diff --git a/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift b/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift index 663ff0c6..78cae1bc 100644 --- a/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift +++ b/Sources/_OpenAPIGeneratorCore/Translator/Responses/TypedResponseHeader.swift @@ -113,7 +113,7 @@ extension FileTranslator { switch header.schemaOrContent { case let .a(schemaContext): schema = schemaContext.schema - codingStrategy = .text + codingStrategy = .uri case let .b(contentMap): guard let typedContent = try bestSingleTypedContent( diff --git a/Sources/swift-openapi-generator/Documentation.docc/Articles/Supported-OpenAPI-features.md b/Sources/swift-openapi-generator/Documentation.docc/Articles/Supported-OpenAPI-features.md index b96caa26..880228f1 100644 --- a/Sources/swift-openapi-generator/Documentation.docc/Articles/Supported-OpenAPI-features.md +++ b/Sources/swift-openapi-generator/Documentation.docc/Articles/Supported-OpenAPI-features.md @@ -210,10 +210,7 @@ Supported features are always provided on _both_ client and server. - [ ] matrix (in path) - [ ] label (in path) -- [ ] form (in query) - - [x] primitive - - [x] array - - [ ] object +- [x] form (in query) - [ ] form (in cookie) - [x] simple (in path) - [x] simple (in header) @@ -221,10 +218,14 @@ Supported features are always provided on _both_ client and server. - [ ] pipeDelimited (in query) - [ ] deepObject (in query) -Supported location + styles + exploded combinations: -- path + simple + false -- query + form + true/false -- header + simple + false +#### Supported combinations + +| Location | Style | Explode | +| -------- | ----- | ------- | +| path | `simple` | `false` | +| query | `form` | `true` | +| query | `form` | `false` | +| header | `simple` | `false` | #### Reference Object diff --git a/Sources/swift-openapi-generator/Documentation.docc/Development/Converting-between-data-and-Swift-types.md b/Sources/swift-openapi-generator/Documentation.docc/Development/Converting-between-data-and-Swift-types.md index f05d94fb..9c6ee3cc 100644 --- a/Sources/swift-openapi-generator/Documentation.docc/Development/Converting-between-data-and-Swift-types.md +++ b/Sources/swift-openapi-generator/Documentation.docc/Development/Converting-between-data-and-Swift-types.md @@ -15,13 +15,23 @@ Most of the functionality of `Converter` is implemented as helper methods in ext Some helper methods can be reused between client and server code, such as headers, but most can't. It's important that we only generalize (move helper methods into common extensions) if the client and server variants would have been exact copies. However, if there are differences, prefer to keep them separate and optimize each variant (for client or server) separately. -### Generated code and generics interaction +The converter, it contains helper methods for all the supported combinations of an schema location, a "coding strategy" and a Swift type. -As outlined in , we aim to minimize the complexity of the generator and rely on the Swift compiler to help ensure that if generated code compiles, it's likely to work correctly. +### Codable and coders -To that end, if the input OpenAPI document contains an input that Swift OpenAPI Generator doesn't support, our first preference is to catch it in the generator and emit a descriptive diagnostic. However, there are cases where that is prohibitively complex, and we let the Swift compiler ensure that, for example, an array of strings cannot be used as a path parameter. In this example case, the generator emits code with the path parameter being of Swift type `[String]`, but since there doesn't exist a converter method for it, it will fail to build. This is considered expected behavior. +The project uses multiple encoder and decoder implementations that all utilize the `Codable` conformance of generated and built-in types. -In the case of the converter, it contains helper methods for all the supported combinations of an schema location, a "coding strategy" and a Swift type. +At the time of writing, the list of coders used is as follows. + +| Format | Encoder | Decoder | Supported in | +| ------ | ------- | ------- | ----- | +| JSON | `Foundation.JSONEncoder` | `Foundation.JSONDecoder` | Bodies, headers | +| URI (†) | `OpenAPIRuntime.URIEncoder` | `OpenAPIRuntime.URIDecoder` | Path, query, headers | +| Plain text | `OpenAPIRuntime.StringEncoder` | `OpenAPIRuntime.StringDecoder` | Bodies | + +> †: Configurable implementation of variable expansion from URI Template (RFC 6570), the `application/x-www-form-urlencoded` serialization from RFC 1866, and OpenAPI 3.0.3. For details of the supported combinations, review . + +While the generator attempts to catch invalid inputs at generation time, there are still combinations of `Codable` types and locations that aren't compatible, and will only get caught at runtime by the specific coder implementation. For example, one could ask the `StringEncoder` to encode an array, but the encoder will throw an error, as containers are not supported in that encoder. ### Dimensions of helper methods @@ -36,24 +46,20 @@ Below is a list of the "dimensions" across which the helper methods differ: - request body - response header fields - response body -- **Coding strategy** represents the chosen encoder/decoder to convert the Swift type to/from data. Values: +- **Coding strategy** represents the chosen coder to convert between the Swift type and data. Supported options: - `JSON` - - example: `application/json` - - uses the type's `Codable` implementation and `JSONEncoder`/`JSONDecoder` - - `text` - - example: `text/plain` - - uses the type's `LosslessStringConvertible` implementation, except for `Foundation.Date`, which uses a system date formatter + - example content type: `application/json` and any with the `+json` suffix + - `{"color": "red", "power": 24}` + - `URI` + - example: query, path, header parameters + - `color=red&power=24` + - `string` + - example: `text/plain`, and any other `text/*` content type + - `"red color and power of 24"` - `binary` - example: `application/octet-stream` - - doesn't transform the binary data, just passes it through - serves as the fallback for content types that don't have more specific handling -- **Swift type** represents the generated type in Swift that best represents the JSON schema defined in the OpenAPI document. For example, a `string` schema is generated as `Swift.String`, an `object` schema is generated as a Swift structure, and an `array` schema is generated as a `Swift.Array` generic over the element type. For the helper methods, it's important which protocol they conform to, as those are used for serialization. Values: - - _string-convertible_ refers to types that conform to `LosslessStringConvertible` - - _array of string-convertibles_ refers to an array of types that conform to `LosslessStringConvertible` - - _date-time_ is represented by `Foundation.Date` - - _array of date-times_ refers to an array of `Foundation.Date` - - _codable_ refers to types that conform to `Codable` - - _data_ is represented by `Foundation.Data` + - doesn't transform the binary data, just passes it through - **Optional/required** represents whether the method works with optional values. Values: - _required_ represents a special overload only for required values - _optional_ represents a special overload only for optional values @@ -72,58 +78,34 @@ method name: {set,get}{required/optional/omit if both}{location}As{strategy} method parameters: value or type of value ``` -| Client/server | Set/get | Schema location | Coding strategy | Swift type | Optional/required | Method name | -| --------------| ------- | --------------- | --------------- | ---------- | ------------------| ----------- | -| common | set | header field | text | string-convertible | both | setHeaderFieldAsText | -| common | set | header field | text | array of string-convertibles | both | setHeaderFieldAsText | -| common | set | header field | text | date | both | setHeaderFieldAsText | -| common | set | header field | text | array of dates | both | setHeaderFieldAsText | -| common | set | header field | JSON | codable | both | setHeaderFieldAsJSON | -| common | get | header field | text | string-convertible | optional | getOptionalHeaderFieldAsText | -| common | get | header field | text | string-convertible | required | getRequiredHeaderFieldAsText | -| common | get | header field | text | array of string-convertibles | optional | getOptionalHeaderFieldAsText | -| common | get | header field | text | array of string-convertibles | required | getRequiredHeaderFieldAsText | -| common | get | header field | text | date | optional | getOptionalHeaderFieldAsText | -| common | get | header field | text | date | required | getRequiredHeaderFieldAsText | -| common | get | header field | text | array of dates | optional | getOptionalHeaderFieldAsText | -| common | get | header field | text | array of dates | required | getRequiredHeaderFieldAsText | -| common | get | header field | JSON | codable | optional | getOptionalHeaderFieldAsJSON | -| common | get | header field | JSON | codable | required | getRequiredHeaderFieldAsJSON | -| client | set | request path | text | string-convertible | required | renderedRequestPath | -| client | set | request query | text | string-convertible | both | setQueryItemAsText | -| client | set | request query | text | array of string-convertibles | both | setQueryItemAsText | -| client | set | request query | text | date | both | setQueryItemAsText | -| client | set | request query | text | array of dates | both | setQueryItemAsText | -| client | set | request body | text | string-convertible | optional | setOptionalRequestBodyAsText | -| client | set | request body | text | string-convertible | required | setRequiredRequestBodyAsText | -| client | set | request body | text | date | optional | setOptionalRequestBodyAsText | -| client | set | request body | text | date | required | setRequiredRequestBodyAsText | -| client | set | request body | JSON | codable | optional | setOptionalRequestBodyAsJSON | -| client | set | request body | JSON | codable | required | setRequiredRequestBodyAsJSON | -| client | set | request body | binary | data | optional | setOptionalRequestBodyAsBinary | -| client | set | request body | binary | data | required | setRequiredRequestBodyAsBinary | -| client | get | response body | text | string-convertible | required | getResponseBodyAsText | -| client | get | response body | text | date | required | getResponseBodyAsText | -| client | get | response body | JSON | codable | required | getResponseBodyAsJSON | -| client | get | response body | binary | data | required | getResponseBodyAsBinary | -| server | get | request path | text | string-convertible | required | getPathParameterAsText | -| server | get | request query | text | string-convertible | optional | getOptionalQueryItemAsText | -| server | get | request query | text | string-convertible | required | getRequiredQueryItemAsText | -| server | get | request query | text | array of string-convertibles | optional | getOptionalQueryItemAsText | -| server | get | request query | text | array of string-convertibles | required | getRequiredQueryItemAsText | -| server | get | request query | text | date | optional | getOptionalQueryItemAsText | -| server | get | request query | text | date | required | getRequiredQueryItemAsText | -| server | get | request query | text | array of dates | optional | getOptionalQueryItemAsText | -| server | get | request query | text | array of dates | required | getRequiredQueryItemAsText | -| server | get | request body | text | string-convertible | optional | getOptionalRequestBodyAsText | -| server | get | request body | text | string-convertible | required | getRequiredRequestBodyAsText | -| server | get | request body | text | date | optional | getOptionalRequestBodyAsText | -| server | get | request body | text | date | required | getRequiredRequestBodyAsText | -| server | get | request body | JSON | codable | optional | getOptionalRequestBodyAsJSON | -| server | get | request body | JSON | codable | required | getRequiredRequestBodyAsJSON | -| server | get | request body | binary | data | optional | getOptionalRequestBodyAsBinary | -| server | get | request body | binary | data | required | getRequiredRequestBodyAsBinary | -| server | set | response body | text | string-convertible | required | setResponseBodyAsText | -| server | set | response body | text | date | required | setResponseBodyAsText | -| server | set | response body | JSON | codable | required | setResponseBodyAsJSON | -| server | set | response body | binary | data | required | setResponseBodyAsBinary | +| Client/server | Set/get | Schema location | Coding strategy | Optional/required | Method name | +| --------------| ------- | --------------- | --------------- | ------------------| ----------- | +| common | set | header field | URI | both | setHeaderFieldAsURI | +| common | set | header field | JSON | both | setHeaderFieldAsJSON | +| common | get | header field | URI | optional | getOptionalHeaderFieldAsURI | +| common | get | header field | URI | required | getRequiredHeaderFieldAsURI | +| common | get | header field | JSON | optional | getOptionalHeaderFieldAsJSON | +| common | get | header field | JSON | required | getRequiredHeaderFieldAsJSON | +| client | set | request path | URI | required | renderedPath | +| client | set | request query | URI | both | setQueryItemAsURI | +| client | set | request body | string | optional | setOptionalRequestBodyAsString | +| client | set | request body | string | required | setRequiredRequestBodyAsString | +| client | set | request body | JSON | optional | setOptionalRequestBodyAsJSON | +| client | set | request body | JSON | required | setRequiredRequestBodyAsJSON | +| client | set | request body | binary | optional | setOptionalRequestBodyAsBinary | +| client | set | request body | binary | required | setRequiredRequestBodyAsBinary | +| client | get | response body | string | required | getResponseBodyAsString | +| client | get | response body | JSON | required | getResponseBodyAsJSON | +| client | get | response body | binary | required | getResponseBodyAsBinary | +| server | get | request path | URI | required | getPathParameterAsURI | +| server | get | request query | URI | optional | getOptionalQueryItemAsURI | +| server | get | request query | URI | required | getRequiredQueryItemAsURI | +| server | get | request body | string | optional | getOptionalRequestBodyAsString | +| server | get | request body | string | required | getRequiredRequestBodyAsString | +| server | get | request body | JSON | optional | getOptionalRequestBodyAsJSON | +| server | get | request body | JSON | required | getRequiredRequestBodyAsJSON | +| server | get | request body | binary | optional | getOptionalRequestBodyAsBinary | +| server | get | request body | binary | required | getRequiredRequestBodyAsBinary | +| server | set | response body | string | required | setResponseBodyAsString | +| server | set | response body | JSON | required | setResponseBodyAsJSON | +| server | set | response body | binary | required | setResponseBodyAsBinary | diff --git a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Client.swift b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Client.swift index f92208d4..a485ed8e 100644 --- a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Client.swift +++ b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Client.swift @@ -40,79 +40,68 @@ public struct Client: APIProtocol { /// /// - Remark: HTTP `GET /pets`. /// - Remark: Generated from `#/paths//pets/get(listPets)`. - public func listPets(_ input: Operations.listPets.Input) async throws - -> Operations.listPets.Output - { + public func listPets(_ input: Operations.listPets.Input) async throws -> Operations.listPets.Output { try await client.send( input: input, forOperation: Operations.listPets.id, - serializer: { input in - let path = try converter.renderedRequestPath(template: "/pets", parameters: []) + serializer: { input in let path = try converter.renderedPath(template: "/pets", parameters: []) var request: OpenAPIRuntime.Request = .init(path: path, method: .get) suppressMutabilityWarning(&request) - try converter.setQueryItemAsText( + try converter.setQueryItemAsURI( in: &request, style: .form, explode: true, name: "limit", value: input.query.limit ) - try converter.setQueryItemAsText( + try converter.setQueryItemAsURI( in: &request, style: .form, explode: true, name: "habitat", value: input.query.habitat ) - try converter.setQueryItemAsText( + try converter.setQueryItemAsURI( in: &request, style: .form, explode: true, name: "feeds", value: input.query.feeds ) - try converter.setHeaderFieldAsText( + try converter.setHeaderFieldAsURI( in: &request.headerFields, name: "My-Request-UUID", value: input.headers.My_Request_UUID ) - try converter.setQueryItemAsText( + try converter.setQueryItemAsURI( in: &request, style: .form, explode: true, name: "since", value: input.query.since ) - converter.setAcceptHeader( - in: &request.headerFields, - contentTypes: input.headers.accept - ) + converter.setAcceptHeader(in: &request.headerFields, contentTypes: input.headers.accept) return request }, deserializer: { response in switch response.statusCode { case 200: let headers: Operations.listPets.Output.Ok.Headers = .init( - My_Response_UUID: try converter.getRequiredHeaderFieldAsText( + My_Response_UUID: try converter.getRequiredHeaderFieldAsURI( in: response.headerFields, name: "My-Response-UUID", as: Swift.String.self ), - My_Tracing_Header: try converter.getOptionalHeaderFieldAsText( + My_Tracing_Header: try converter.getOptionalHeaderFieldAsURI( in: response.headerFields, name: "My-Tracing-Header", as: Components.Headers.TracingHeader.self ) ) - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.listPets.Output.Ok.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Components.Schemas.Pets.self, @@ -125,15 +114,10 @@ public struct Client: APIProtocol { return .ok(.init(headers: headers, body: body)) default: let headers: Operations.listPets.Output.Default.Headers = .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.listPets.Output.Default.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Components.Schemas._Error.self, @@ -143,10 +127,7 @@ public struct Client: APIProtocol { } else { throw converter.makeUnexpectedContentTypeError(contentType: contentType) } - return .`default`( - statusCode: response.statusCode, - .init(headers: headers, body: body) - ) + return .`default`(statusCode: response.statusCode, .init(headers: headers, body: body)) } } ) @@ -155,14 +136,11 @@ public struct Client: APIProtocol { /// /// - Remark: HTTP `POST /pets`. /// - Remark: Generated from `#/paths//pets/post(createPet)`. - public func createPet(_ input: Operations.createPet.Input) async throws - -> Operations.createPet.Output - { + public func createPet(_ input: Operations.createPet.Input) async throws -> Operations.createPet.Output { try await client.send( input: input, forOperation: Operations.createPet.id, - serializer: { input in - let path = try converter.renderedRequestPath(template: "/pets", parameters: []) + serializer: { input in let path = try converter.renderedPath(template: "/pets", parameters: []) var request: OpenAPIRuntime.Request = .init(path: path, method: .post) suppressMutabilityWarning(&request) try converter.setHeaderFieldAsJSON( @@ -170,10 +148,7 @@ public struct Client: APIProtocol { name: "X-Extra-Arguments", value: input.headers.X_Extra_Arguments ) - converter.setAcceptHeader( - in: &request.headerFields, - contentTypes: input.headers.accept - ) + converter.setAcceptHeader(in: &request.headerFields, contentTypes: input.headers.accept) switch input.body { case let .json(value): request.body = try converter.setRequiredRequestBodyAsJSON( @@ -194,15 +169,10 @@ public struct Client: APIProtocol { as: Components.Schemas.CodeError.self ) ) - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.createPet.Output.Created.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Components.Schemas.Pet.self, @@ -215,21 +185,16 @@ public struct Client: APIProtocol { return .created(.init(headers: headers, body: body)) case 400...499: let headers: Components.Responses.ErrorBadRequest.Headers = .init( - X_Reason: try converter.getOptionalHeaderFieldAsText( + X_Reason: try converter.getOptionalHeaderFieldAsURI( in: response.headerFields, name: "X-Reason", as: Swift.String.self ) ) - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Components.Responses.ErrorBadRequest.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Components.Responses.ErrorBadRequest.Body.jsonPayload.self, @@ -239,10 +204,7 @@ public struct Client: APIProtocol { } else { throw converter.makeUnexpectedContentTypeError(contentType: contentType) } - return .clientError( - statusCode: response.statusCode, - .init(headers: headers, body: body) - ) + return .clientError(statusCode: response.statusCode, .init(headers: headers, body: body)) default: return .undocumented(statusCode: response.statusCode, .init()) } } @@ -250,38 +212,24 @@ public struct Client: APIProtocol { } /// - Remark: HTTP `GET /pets/stats`. /// - Remark: Generated from `#/paths//pets/stats/get(getStats)`. - public func getStats(_ input: Operations.getStats.Input) async throws - -> Operations.getStats.Output - { + public func getStats(_ input: Operations.getStats.Input) async throws -> Operations.getStats.Output { try await client.send( input: input, forOperation: Operations.getStats.id, - serializer: { input in - let path = try converter.renderedRequestPath( - template: "/pets/stats", - parameters: [] - ) + serializer: { input in let path = try converter.renderedPath(template: "/pets/stats", parameters: []) var request: OpenAPIRuntime.Request = .init(path: path, method: .get) suppressMutabilityWarning(&request) - converter.setAcceptHeader( - in: &request.headerFields, - contentTypes: input.headers.accept - ) + converter.setAcceptHeader(in: &request.headerFields, contentTypes: input.headers.accept) return request }, deserializer: { response in switch response.statusCode { case 200: let headers: Operations.getStats.Output.Ok.Headers = .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.getStats.Output.Ok.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Components.Schemas.PetStats.self, @@ -299,17 +247,11 @@ public struct Client: APIProtocol { } /// - Remark: HTTP `POST /pets/stats`. /// - Remark: Generated from `#/paths//pets/stats/post(postStats)`. - public func postStats(_ input: Operations.postStats.Input) async throws - -> Operations.postStats.Output - { + public func postStats(_ input: Operations.postStats.Input) async throws -> Operations.postStats.Output { try await client.send( input: input, forOperation: Operations.postStats.id, - serializer: { input in - let path = try converter.renderedRequestPath( - template: "/pets/stats", - parameters: [] - ) + serializer: { input in let path = try converter.renderedPath(template: "/pets/stats", parameters: []) var request: OpenAPIRuntime.Request = .init(path: path, method: .post) suppressMutabilityWarning(&request) switch input.body { @@ -334,14 +276,12 @@ public struct Client: APIProtocol { } /// - Remark: HTTP `POST /probe/`. /// - Remark: Generated from `#/paths//probe//post(probe)`. - @available(*, deprecated) public func probe(_ input: Operations.probe.Input) async throws - -> Operations.probe.Output + @available(*, deprecated) public func probe(_ input: Operations.probe.Input) async throws -> Operations.probe.Output { try await client.send( input: input, forOperation: Operations.probe.id, - serializer: { input in - let path = try converter.renderedRequestPath(template: "/probe/", parameters: []) + serializer: { input in let path = try converter.renderedPath(template: "/probe/", parameters: []) var request: OpenAPIRuntime.Request = .init(path: path, method: .post) suppressMutabilityWarning(&request) return request @@ -360,23 +300,15 @@ public struct Client: APIProtocol { /// /// - Remark: HTTP `PATCH /pets/{petId}`. /// - Remark: Generated from `#/paths//pets/{petId}/patch(updatePet)`. - public func updatePet(_ input: Operations.updatePet.Input) async throws - -> Operations.updatePet.Output - { + public func updatePet(_ input: Operations.updatePet.Input) async throws -> Operations.updatePet.Output { try await client.send( input: input, forOperation: Operations.updatePet.id, serializer: { input in - let path = try converter.renderedRequestPath( - template: "/pets/{}", - parameters: [input.path.petId] - ) + let path = try converter.renderedPath(template: "/pets/{}", parameters: [input.path.petId]) var request: OpenAPIRuntime.Request = .init(path: path, method: .patch) suppressMutabilityWarning(&request) - converter.setAcceptHeader( - in: &request.headerFields, - contentTypes: input.headers.accept - ) + converter.setAcceptHeader(in: &request.headerFields, contentTypes: input.headers.accept) switch input.body { case .none: request.body = nil case let .json(value): @@ -395,15 +327,10 @@ public struct Client: APIProtocol { return .noContent(.init(headers: headers, body: nil)) case 400: let headers: Operations.updatePet.Output.BadRequest.Headers = .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.updatePet.Output.BadRequest.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Operations.updatePet.Output.BadRequest.Body.jsonPayload.self, @@ -430,16 +357,10 @@ public struct Client: APIProtocol { input: input, forOperation: Operations.uploadAvatarForPet.id, serializer: { input in - let path = try converter.renderedRequestPath( - template: "/pets/{}/avatar", - parameters: [input.path.petId] - ) + let path = try converter.renderedPath(template: "/pets/{}/avatar", parameters: [input.path.petId]) var request: OpenAPIRuntime.Request = .init(path: path, method: .put) suppressMutabilityWarning(&request) - converter.setAcceptHeader( - in: &request.headerFields, - contentTypes: input.headers.accept - ) + converter.setAcceptHeader(in: &request.headerFields, contentTypes: input.headers.accept) switch input.body { case let .binary(value): request.body = try converter.setRequiredRequestBodyAsBinary( @@ -454,9 +375,7 @@ public struct Client: APIProtocol { switch response.statusCode { case 200: let headers: Operations.uploadAvatarForPet.Output.Ok.Headers = .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.uploadAvatarForPet.Output.Ok.Body if try contentType == nil || converter.isMatchingContentType( @@ -474,17 +393,11 @@ public struct Client: APIProtocol { } return .ok(.init(headers: headers, body: body)) case 412: - let headers: Operations.uploadAvatarForPet.Output.PreconditionFailed.Headers = - .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let headers: Operations.uploadAvatarForPet.Output.PreconditionFailed.Headers = .init() + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.uploadAvatarForPet.Output.PreconditionFailed.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Swift.String.self, @@ -496,19 +409,13 @@ public struct Client: APIProtocol { } return .preconditionFailed(.init(headers: headers, body: body)) case 500: - let headers: Operations.uploadAvatarForPet.Output.InternalServerError.Headers = - .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let headers: Operations.uploadAvatarForPet.Output.InternalServerError.Headers = .init() + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.uploadAvatarForPet.Output.InternalServerError.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "text/plain" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "text/plain") { - body = try converter.getResponseBodyAsText( + body = try converter.getResponseBodyAsString( Swift.String.self, from: response.body, transforming: { value in .text(value) } diff --git a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Server.swift b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Server.swift index b2665df5..c60a7a9f 100644 --- a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Server.swift +++ b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Server.swift @@ -85,29 +85,29 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { using: { APIHandler.listPets($0) }, deserializer: { request, metadata in let path: Operations.listPets.Input.Path = .init() let query: Operations.listPets.Input.Query = .init( - limit: try converter.getOptionalQueryItemAsText( - in: metadata.queryParameters, + limit: try converter.getOptionalQueryItemAsURI( + in: request.query, style: .form, explode: true, name: "limit", as: Swift.Int32.self ), - habitat: try converter.getOptionalQueryItemAsText( - in: metadata.queryParameters, + habitat: try converter.getOptionalQueryItemAsURI( + in: request.query, style: .form, explode: true, name: "habitat", as: Operations.listPets.Input.Query.habitatPayload.self ), - feeds: try converter.getOptionalQueryItemAsText( - in: metadata.queryParameters, + feeds: try converter.getOptionalQueryItemAsURI( + in: request.query, style: .form, explode: true, name: "feeds", as: Operations.listPets.Input.Query.feedsPayload.self ), - since: try converter.getOptionalQueryItemAsText( - in: metadata.queryParameters, + since: try converter.getOptionalQueryItemAsURI( + in: request.query, style: .form, explode: true, name: "since", @@ -115,7 +115,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { ) ) let headers: Operations.listPets.Input.Headers = .init( - My_Request_UUID: try converter.getOptionalHeaderFieldAsText( + My_Request_UUID: try converter.getOptionalHeaderFieldAsURI( in: request.headerFields, name: "My-Request-UUID", as: Swift.String.self @@ -137,22 +137,19 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressUnusedWarning(value) var response = Response(statusCode: 200) suppressMutabilityWarning(&response) - try converter.setHeaderFieldAsText( + try converter.setHeaderFieldAsURI( in: &response.headerFields, name: "My-Response-UUID", value: value.headers.My_Response_UUID ) - try converter.setHeaderFieldAsText( + try converter.setHeaderFieldAsURI( in: &response.headerFields, name: "My-Tracing-Header", value: value.headers.My_Tracing_Header ) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -166,10 +163,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -205,10 +199,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { let contentType = converter.extractContentTypeIfPresent(in: request.headerFields) let body: Operations.createPet.Input.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getRequiredRequestBodyAsJSON( Components.Schemas.CreatePetRequest.self, @@ -239,10 +230,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { ) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -254,17 +242,14 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressUnusedWarning(value) var response = Response(statusCode: statusCode) suppressMutabilityWarning(&response) - try converter.setHeaderFieldAsText( + try converter.setHeaderFieldAsURI( in: &response.headerFields, name: "X-Reason", value: value.headers.X_Reason ) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -307,10 +292,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -338,10 +320,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { let contentType = converter.extractContentTypeIfPresent(in: request.headerFields) let body: Operations.postStats.Input.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getRequiredRequestBodyAsJSON( Components.Schemas.PetStats.self, @@ -373,9 +352,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { } /// - Remark: HTTP `POST /probe/`. /// - Remark: Generated from `#/paths//probe//post(probe)`. - @available(*, deprecated) func probe(request: Request, metadata: ServerRequestMetadata) - async throws -> Response - { + @available(*, deprecated) func probe(request: Request, metadata: ServerRequestMetadata) async throws -> Response { try await handle( request: request, with: metadata, @@ -385,13 +362,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { let query: Operations.probe.Input.Query = .init() let headers: Operations.probe.Input.Headers = .init() let cookies: Operations.probe.Input.Cookies = .init() - return Operations.probe.Input( - path: path, - query: query, - headers: headers, - cookies: cookies, - body: nil - ) + return Operations.probe.Input(path: path, query: query, headers: headers, cookies: cookies, body: nil) }, serializer: { output, request in switch output { @@ -417,7 +388,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { using: { APIHandler.updatePet($0) }, deserializer: { request, metadata in let path: Operations.updatePet.Input.Path = .init( - petId: try converter.getPathParameterAsText( + petId: try converter.getPathParameterAsURI( in: metadata.pathParameters, name: "petId", as: Swift.Int64.self @@ -431,10 +402,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { let contentType = converter.extractContentTypeIfPresent(in: request.headerFields) let body: Components.RequestBodies.UpdatePetRequest? if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getOptionalRequestBodyAsJSON( Components.RequestBodies.UpdatePetRequest.jsonPayload.self, @@ -465,10 +433,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -485,9 +450,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { /// /// - Remark: HTTP `PUT /pets/{petId}/avatar`. /// - Remark: Generated from `#/paths//pets/{petId}/avatar/put(uploadAvatarForPet)`. - func uploadAvatarForPet(request: Request, metadata: ServerRequestMetadata) async throws - -> Response - { + func uploadAvatarForPet(request: Request, metadata: ServerRequestMetadata) async throws -> Response { try await handle( request: request, with: metadata, @@ -495,7 +458,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { using: { APIHandler.uploadAvatarForPet($0) }, deserializer: { request, metadata in let path: Operations.uploadAvatarForPet.Input.Path = .init( - petId: try converter.getPathParameterAsText( + petId: try converter.getPathParameterAsURI( in: metadata.pathParameters, name: "petId", as: Components.Parameters.path_petId.self @@ -509,10 +472,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { let contentType = converter.extractContentTypeIfPresent(in: request.headerFields) let body: Operations.uploadAvatarForPet.Input.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/octet-stream" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/octet-stream") { body = try converter.getRequiredRequestBodyAsBinary( Foundation.Data.self, @@ -538,10 +498,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .binary(value): - try converter.validateAcceptIfPresent( - "application/octet-stream", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/octet-stream", in: request.headerFields) response.body = try converter.setResponseBodyAsBinary( value, headerFields: &response.headerFields, @@ -555,10 +512,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -572,11 +526,8 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .text(value): - try converter.validateAcceptIfPresent( - "text/plain", - in: request.headerFields - ) - response.body = try converter.setResponseBodyAsText( + try converter.validateAcceptIfPresent("text/plain", in: request.headerFields) + response.body = try converter.setResponseBodyAsString( value, headerFields: &response.headerFields, contentType: "text/plain" diff --git a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Types.swift b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Types.swift index 37435217..78c889aa 100644 --- a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Types.swift +++ b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore/Types.swift @@ -28,8 +28,7 @@ public protocol APIProtocol: Sendable { func postStats(_ input: Operations.postStats.Input) async throws -> Operations.postStats.Output /// - Remark: HTTP `POST /probe/`. /// - Remark: Generated from `#/paths//probe//post(probe)`. - @available(*, deprecated) func probe(_ input: Operations.probe.Input) async throws - -> Operations.probe.Output + @available(*, deprecated) func probe(_ input: Operations.probe.Input) async throws -> Operations.probe.Output /// Update just a specific property of an existing pet. Nothing is updated if no request body is provided. /// /// - Remark: HTTP `PATCH /pets/{petId}`. @@ -45,9 +44,7 @@ public protocol APIProtocol: Sendable { /// Server URLs defined in the OpenAPI document. public enum Servers { /// Example Petstore implementation service - public static func server1() throws -> URL { - try URL(validatingOpenAPIServerURL: "https://example.com/api") - } + public static func server1() throws -> URL { try URL(validatingOpenAPIServerURL: "https://example.com/api") } public static func server2() throws -> URL { try URL(validatingOpenAPIServerURL: "/api") } } /// Types generated from the components section of the OpenAPI document. @@ -98,10 +95,7 @@ public enum Components { /// Kind of pet /// /// - Remark: Generated from `#/components/schemas/PetKind`. - @frozen - public enum PetKind: RawRepresentable, Codable, Hashable, Sendable, - _AutoLosslessStringConvertible, CaseIterable - { + @frozen public enum PetKind: RawRepresentable, Codable, Hashable, Sendable, CaseIterable { case cat case dog case ELEPHANT @@ -132,9 +126,7 @@ public enum Components { case ._public: return "public" } } - public static var allCases: [Self] { - [.cat, .dog, .ELEPHANT, .BIG_ELEPHANT_1, ._nake, ._public] - } + public static var allCases: [Self] { [.cat, .dog, .ELEPHANT, .BIG_ELEPHANT_1, ._nake, ._public] } } /// - Remark: Generated from `#/components/schemas/CreatePetRequest`. public struct CreatePetRequest: Codable, Hashable, Sendable { @@ -150,11 +142,7 @@ public enum Components { /// - name: /// - kind: /// - tag: - public init( - name: Swift.String, - kind: Components.Schemas.PetKind? = nil, - tag: Swift.String? = nil - ) { + public init(name: Swift.String, kind: Components.Schemas.PetKind? = nil, tag: Swift.String? = nil) { self.name = name self.kind = kind self.tag = tag @@ -209,10 +197,7 @@ public enum Components { /// - Remark: Generated from `#/components/schemas/PetFeeding`. public struct PetFeeding: Codable, Hashable, Sendable { /// - Remark: Generated from `#/components/schemas/PetFeeding/schedule`. - @frozen - public enum schedulePayload: RawRepresentable, Codable, Hashable, Sendable, - _AutoLosslessStringConvertible, CaseIterable - { + @frozen public enum schedulePayload: RawRepresentable, Codable, Hashable, Sendable, CaseIterable { case hourly case daily case weekly @@ -242,9 +227,7 @@ public enum Components { /// /// - Parameters: /// - schedule: - public init(schedule: Components.Schemas.PetFeeding.schedulePayload? = nil) { - self.schedule = schedule - } + public init(schedule: Components.Schemas.PetFeeding.schedulePayload? = nil) { self.schedule = schedule } public enum CodingKeys: String, CodingKey { case schedule } } /// - Remark: Generated from `#/components/schemas/DOB`. @@ -278,10 +261,8 @@ public enum Components { /// - Parameters: /// - foo: /// - additionalProperties: A container of undocumented properties. - public init( - foo: Swift.String? = nil, - additionalProperties: OpenAPIRuntime.OpenAPIObjectContainer = .init() - ) { + public init(foo: Swift.String? = nil, additionalProperties: OpenAPIRuntime.OpenAPIObjectContainer = .init()) + { self.foo = foo self.additionalProperties = additionalProperties } @@ -308,10 +289,7 @@ public enum Components { /// - Parameters: /// - foo: /// - additionalProperties: A container of undocumented properties. - public init( - foo: Swift.String? = nil, - additionalProperties: [String: Swift.Int] = .init() - ) { + public init(foo: Swift.String? = nil, additionalProperties: [String: Swift.Int] = .init()) { self.foo = foo self.additionalProperties = additionalProperties } @@ -360,10 +338,7 @@ public enum Components { /// - Parameters: /// - value1: /// - value2: - public init( - value1: Components.Schemas.AllOfObjects.Value1Payload, - value2: Components.Schemas.CodeError - ) { + public init(value1: Components.Schemas.AllOfObjects.Value1Payload, value2: Components.Schemas.CodeError) { self.value1 = value1 self.value2 = value2 } @@ -576,9 +551,7 @@ public enum Components { @available(*, deprecated) public struct DeprecatedObject: Codable, Hashable, Sendable { /// Creates a new `DeprecatedObject`. public init() {} - public init(from decoder: any Decoder) throws { - try decoder.ensureNoAdditionalProperties(knownKeys: []) - } + public init(from decoder: any Decoder) throws { try decoder.ensureNoAdditionalProperties(knownKeys: []) } } /// - Remark: Generated from `#/components/schemas/ObjectWithDeprecatedProperty`. public struct ObjectWithDeprecatedProperty: Codable, Hashable, Sendable { @@ -739,10 +712,7 @@ public enum Operations { /// - Remark: Generated from `#/paths/pets/GET/query/limit`. public var limit: Swift.Int32? /// - Remark: Generated from `#/paths/pets/GET/query/habitat`. - @frozen - public enum habitatPayload: RawRepresentable, Codable, Hashable, Sendable, - _AutoLosslessStringConvertible, CaseIterable - { + @frozen public enum habitatPayload: RawRepresentable, Codable, Hashable, Sendable, CaseIterable { case water case land case air @@ -772,10 +742,7 @@ public enum Operations { /// - Remark: Generated from `#/paths/pets/GET/query/habitat`. public var habitat: Operations.listPets.Input.Query.habitatPayload? /// - Remark: Generated from `#/paths/pets/GET/query/feedsPayload`. - @frozen - public enum feedsPayloadPayload: RawRepresentable, Codable, Hashable, Sendable, - _AutoLosslessStringConvertible, CaseIterable - { + @frozen public enum feedsPayloadPayload: RawRepresentable, Codable, Hashable, Sendable, CaseIterable { case omnivore case carnivore case herbivore @@ -800,8 +767,7 @@ public enum Operations { public static var allCases: [Self] { [.omnivore, .carnivore, .herbivore] } } /// - Remark: Generated from `#/paths/pets/GET/query/feeds`. - public typealias feedsPayload = [Operations.listPets.Input.Query - .feedsPayloadPayload] + public typealias feedsPayload = [Operations.listPets.Input.Query.feedsPayloadPayload] /// - Remark: Generated from `#/paths/pets/GET/query/feeds`. public var feeds: Operations.listPets.Input.Query.feedsPayload? /// Supply this parameter to filter pets born since the provided date. @@ -834,10 +800,7 @@ public enum Operations { /// /// - Remark: Generated from `#/paths/pets/GET/header/My-Request-UUID`. public var My_Request_UUID: Swift.String? - public var accept: - [OpenAPIRuntime.AcceptHeaderContentType< - Operations.listPets.AcceptableContentType - >] + public var accept: [OpenAPIRuntime.AcceptHeaderContentType] /// Creates a new `Headers`. /// /// - Parameters: @@ -845,9 +808,8 @@ public enum Operations { /// - accept: public init( My_Request_UUID: Swift.String? = nil, - accept: [OpenAPIRuntime.AcceptHeaderContentType< - Operations.listPets.AcceptableContentType - >] = .defaultValues() + accept: [OpenAPIRuntime.AcceptHeaderContentType] = + .defaultValues() ) { self.My_Request_UUID = My_Request_UUID self.accept = accept @@ -924,10 +886,7 @@ public enum Operations { /// - Parameters: /// - headers: Received HTTP response headers /// - body: Received HTTP response body - public init( - headers: Operations.listPets.Output.Ok.Headers, - body: Operations.listPets.Output.Ok.Body - ) { + public init(headers: Operations.listPets.Output.Ok.Headers, body: Operations.listPets.Output.Ok.Body) { self.headers = headers self.body = body } @@ -1016,10 +975,7 @@ public enum Operations { /// /// - Remark: Generated from `#/paths/pets/POST/header/X-Extra-Arguments`. public var X_Extra_Arguments: Components.Schemas.CodeError? - public var accept: - [OpenAPIRuntime.AcceptHeaderContentType< - Operations.createPet.AcceptableContentType - >] + public var accept: [OpenAPIRuntime.AcceptHeaderContentType] /// Creates a new `Headers`. /// /// - Parameters: @@ -1027,9 +983,8 @@ public enum Operations { /// - accept: public init( X_Extra_Arguments: Components.Schemas.CodeError? = nil, - accept: [OpenAPIRuntime.AcceptHeaderContentType< - Operations.createPet.AcceptableContentType - >] = .defaultValues() + accept: [OpenAPIRuntime.AcceptHeaderContentType] = + .defaultValues() ) { self.X_Extra_Arguments = X_Extra_Arguments self.accept = accept @@ -1162,18 +1117,14 @@ public enum Operations { public var query: Operations.getStats.Input.Query /// - Remark: Generated from `#/paths/pets/stats/GET/header`. public struct Headers: Sendable, Hashable { - public var accept: - [OpenAPIRuntime.AcceptHeaderContentType< - Operations.getStats.AcceptableContentType - >] + public var accept: [OpenAPIRuntime.AcceptHeaderContentType] /// Creates a new `Headers`. /// /// - Parameters: /// - accept: public init( - accept: [OpenAPIRuntime.AcceptHeaderContentType< - Operations.getStats.AcceptableContentType - >] = .defaultValues() + accept: [OpenAPIRuntime.AcceptHeaderContentType] = + .defaultValues() ) { self.accept = accept } } public var headers: Operations.getStats.Input.Headers @@ -1481,18 +1432,14 @@ public enum Operations { public var query: Operations.updatePet.Input.Query /// - Remark: Generated from `#/paths/pets/{petId}/PATCH/header`. public struct Headers: Sendable, Hashable { - public var accept: - [OpenAPIRuntime.AcceptHeaderContentType< - Operations.updatePet.AcceptableContentType - >] + public var accept: [OpenAPIRuntime.AcceptHeaderContentType] /// Creates a new `Headers`. /// /// - Parameters: /// - accept: public init( - accept: [OpenAPIRuntime.AcceptHeaderContentType< - Operations.updatePet.AcceptableContentType - >] = .defaultValues() + accept: [OpenAPIRuntime.AcceptHeaderContentType] = + .defaultValues() ) { self.accept = accept } } public var headers: Operations.updatePet.Input.Headers @@ -1654,9 +1601,7 @@ public enum Operations { /// - Remark: Generated from `#/paths/pets/{petId}/avatar/PUT/header`. public struct Headers: Sendable, Hashable { public var accept: - [OpenAPIRuntime.AcceptHeaderContentType< - Operations.uploadAvatarForPet.AcceptableContentType - >] + [OpenAPIRuntime.AcceptHeaderContentType] /// Creates a new `Headers`. /// /// - Parameters: @@ -1758,8 +1703,7 @@ public enum Operations { /// - headers: Received HTTP response headers /// - body: Received HTTP response body public init( - headers: Operations.uploadAvatarForPet.Output.PreconditionFailed.Headers = - .init(), + headers: Operations.uploadAvatarForPet.Output.PreconditionFailed.Headers = .init(), body: Operations.uploadAvatarForPet.Output.PreconditionFailed.Body ) { self.headers = headers @@ -1793,8 +1737,7 @@ public enum Operations { /// - headers: Received HTTP response headers /// - body: Received HTTP response body public init( - headers: Operations.uploadAvatarForPet.Output.InternalServerError.Headers = - .init(), + headers: Operations.uploadAvatarForPet.Output.InternalServerError.Headers = .init(), body: Operations.uploadAvatarForPet.Output.InternalServerError.Body ) { self.headers = headers diff --git a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Client.swift b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Client.swift index ce768275..b5a599c5 100644 --- a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Client.swift +++ b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Client.swift @@ -40,79 +40,68 @@ public struct Client: APIProtocol { /// /// - Remark: HTTP `GET /pets`. /// - Remark: Generated from `#/paths//pets/get(listPets)`. - public func listPets(_ input: Operations.listPets.Input) async throws - -> Operations.listPets.Output - { + public func listPets(_ input: Operations.listPets.Input) async throws -> Operations.listPets.Output { try await client.send( input: input, forOperation: Operations.listPets.id, - serializer: { input in - let path = try converter.renderedRequestPath(template: "/pets", parameters: []) + serializer: { input in let path = try converter.renderedPath(template: "/pets", parameters: []) var request: OpenAPIRuntime.Request = .init(path: path, method: .get) suppressMutabilityWarning(&request) - try converter.setQueryItemAsText( + try converter.setQueryItemAsURI( in: &request, style: .form, explode: true, name: "limit", value: input.query.limit ) - try converter.setQueryItemAsText( + try converter.setQueryItemAsURI( in: &request, style: .form, explode: true, name: "habitat", value: input.query.habitat ) - try converter.setQueryItemAsText( + try converter.setQueryItemAsURI( in: &request, style: .form, explode: true, name: "feeds", value: input.query.feeds ) - try converter.setHeaderFieldAsText( + try converter.setHeaderFieldAsURI( in: &request.headerFields, name: "My-Request-UUID", value: input.headers.My_hyphen_Request_hyphen_UUID ) - try converter.setQueryItemAsText( + try converter.setQueryItemAsURI( in: &request, style: .form, explode: true, name: "since", value: input.query.since ) - converter.setAcceptHeader( - in: &request.headerFields, - contentTypes: input.headers.accept - ) + converter.setAcceptHeader(in: &request.headerFields, contentTypes: input.headers.accept) return request }, deserializer: { response in switch response.statusCode { case 200: let headers: Operations.listPets.Output.Ok.Headers = .init( - My_hyphen_Response_hyphen_UUID: try converter.getRequiredHeaderFieldAsText( + My_hyphen_Response_hyphen_UUID: try converter.getRequiredHeaderFieldAsURI( in: response.headerFields, name: "My-Response-UUID", as: Swift.String.self ), - My_hyphen_Tracing_hyphen_Header: try converter.getOptionalHeaderFieldAsText( + My_hyphen_Tracing_hyphen_Header: try converter.getOptionalHeaderFieldAsURI( in: response.headerFields, name: "My-Tracing-Header", as: Components.Headers.TracingHeader.self ) ) - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.listPets.Output.Ok.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Components.Schemas.Pets.self, @@ -125,15 +114,10 @@ public struct Client: APIProtocol { return .ok(.init(headers: headers, body: body)) default: let headers: Operations.listPets.Output.Default.Headers = .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.listPets.Output.Default.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Components.Schemas._Error.self, @@ -143,10 +127,7 @@ public struct Client: APIProtocol { } else { throw converter.makeUnexpectedContentTypeError(contentType: contentType) } - return .`default`( - statusCode: response.statusCode, - .init(headers: headers, body: body) - ) + return .`default`(statusCode: response.statusCode, .init(headers: headers, body: body)) } } ) @@ -155,14 +136,11 @@ public struct Client: APIProtocol { /// /// - Remark: HTTP `POST /pets`. /// - Remark: Generated from `#/paths//pets/post(createPet)`. - public func createPet(_ input: Operations.createPet.Input) async throws - -> Operations.createPet.Output - { + public func createPet(_ input: Operations.createPet.Input) async throws -> Operations.createPet.Output { try await client.send( input: input, forOperation: Operations.createPet.id, - serializer: { input in - let path = try converter.renderedRequestPath(template: "/pets", parameters: []) + serializer: { input in let path = try converter.renderedPath(template: "/pets", parameters: []) var request: OpenAPIRuntime.Request = .init(path: path, method: .post) suppressMutabilityWarning(&request) try converter.setHeaderFieldAsJSON( @@ -170,10 +148,7 @@ public struct Client: APIProtocol { name: "X-Extra-Arguments", value: input.headers.X_hyphen_Extra_hyphen_Arguments ) - converter.setAcceptHeader( - in: &request.headerFields, - contentTypes: input.headers.accept - ) + converter.setAcceptHeader(in: &request.headerFields, contentTypes: input.headers.accept) switch input.body { case let .json(value): request.body = try converter.setRequiredRequestBodyAsJSON( @@ -194,15 +169,10 @@ public struct Client: APIProtocol { as: Components.Schemas.CodeError.self ) ) - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.createPet.Output.Created.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Components.Schemas.Pet.self, @@ -215,21 +185,16 @@ public struct Client: APIProtocol { return .created(.init(headers: headers, body: body)) case 400...499: let headers: Components.Responses.ErrorBadRequest.Headers = .init( - X_hyphen_Reason: try converter.getOptionalHeaderFieldAsText( + X_hyphen_Reason: try converter.getOptionalHeaderFieldAsURI( in: response.headerFields, name: "X-Reason", as: Swift.String.self ) ) - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Components.Responses.ErrorBadRequest.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Components.Responses.ErrorBadRequest.Body.jsonPayload.self, @@ -239,10 +204,7 @@ public struct Client: APIProtocol { } else { throw converter.makeUnexpectedContentTypeError(contentType: contentType) } - return .clientError( - statusCode: response.statusCode, - .init(headers: headers, body: body) - ) + return .clientError(statusCode: response.statusCode, .init(headers: headers, body: body)) default: return .undocumented(statusCode: response.statusCode, .init()) } } @@ -250,49 +212,32 @@ public struct Client: APIProtocol { } /// - Remark: HTTP `GET /pets/stats`. /// - Remark: Generated from `#/paths//pets/stats/get(getStats)`. - public func getStats(_ input: Operations.getStats.Input) async throws - -> Operations.getStats.Output - { + public func getStats(_ input: Operations.getStats.Input) async throws -> Operations.getStats.Output { try await client.send( input: input, forOperation: Operations.getStats.id, - serializer: { input in - let path = try converter.renderedRequestPath( - template: "/pets/stats", - parameters: [] - ) + serializer: { input in let path = try converter.renderedPath(template: "/pets/stats", parameters: []) var request: OpenAPIRuntime.Request = .init(path: path, method: .get) suppressMutabilityWarning(&request) - converter.setAcceptHeader( - in: &request.headerFields, - contentTypes: input.headers.accept - ) + converter.setAcceptHeader(in: &request.headerFields, contentTypes: input.headers.accept) return request }, deserializer: { response in switch response.statusCode { case 200: let headers: Operations.getStats.Output.Ok.Headers = .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.getStats.Output.Ok.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Components.Schemas.PetStats.self, from: response.body, transforming: { value in .json(value) } ) - } else if try converter.isMatchingContentType( - received: contentType, - expectedRaw: "text/plain" - ) { - body = try converter.getResponseBodyAsText( + } else if try converter.isMatchingContentType(received: contentType, expectedRaw: "text/plain") { + body = try converter.getResponseBodyAsString( Swift.String.self, from: response.body, transforming: { value in .plainText(value) } @@ -317,17 +262,11 @@ public struct Client: APIProtocol { } /// - Remark: HTTP `POST /pets/stats`. /// - Remark: Generated from `#/paths//pets/stats/post(postStats)`. - public func postStats(_ input: Operations.postStats.Input) async throws - -> Operations.postStats.Output - { + public func postStats(_ input: Operations.postStats.Input) async throws -> Operations.postStats.Output { try await client.send( input: input, forOperation: Operations.postStats.id, - serializer: { input in - let path = try converter.renderedRequestPath( - template: "/pets/stats", - parameters: [] - ) + serializer: { input in let path = try converter.renderedPath(template: "/pets/stats", parameters: []) var request: OpenAPIRuntime.Request = .init(path: path, method: .post) suppressMutabilityWarning(&request) switch input.body { @@ -338,7 +277,7 @@ public struct Client: APIProtocol { contentType: "application/json; charset=utf-8" ) case let .plainText(value): - request.body = try converter.setRequiredRequestBodyAsText( + request.body = try converter.setRequiredRequestBodyAsString( value, headerFields: &request.headerFields, contentType: "text/plain" @@ -364,14 +303,12 @@ public struct Client: APIProtocol { } /// - Remark: HTTP `POST /probe/`. /// - Remark: Generated from `#/paths//probe//post(probe)`. - @available(*, deprecated) public func probe(_ input: Operations.probe.Input) async throws - -> Operations.probe.Output + @available(*, deprecated) public func probe(_ input: Operations.probe.Input) async throws -> Operations.probe.Output { try await client.send( input: input, forOperation: Operations.probe.id, - serializer: { input in - let path = try converter.renderedRequestPath(template: "/probe/", parameters: []) + serializer: { input in let path = try converter.renderedPath(template: "/probe/", parameters: []) var request: OpenAPIRuntime.Request = .init(path: path, method: .post) suppressMutabilityWarning(&request) return request @@ -390,23 +327,15 @@ public struct Client: APIProtocol { /// /// - Remark: HTTP `PATCH /pets/{petId}`. /// - Remark: Generated from `#/paths//pets/{petId}/patch(updatePet)`. - public func updatePet(_ input: Operations.updatePet.Input) async throws - -> Operations.updatePet.Output - { + public func updatePet(_ input: Operations.updatePet.Input) async throws -> Operations.updatePet.Output { try await client.send( input: input, forOperation: Operations.updatePet.id, serializer: { input in - let path = try converter.renderedRequestPath( - template: "/pets/{}", - parameters: [input.path.petId] - ) + let path = try converter.renderedPath(template: "/pets/{}", parameters: [input.path.petId]) var request: OpenAPIRuntime.Request = .init(path: path, method: .patch) suppressMutabilityWarning(&request) - converter.setAcceptHeader( - in: &request.headerFields, - contentTypes: input.headers.accept - ) + converter.setAcceptHeader(in: &request.headerFields, contentTypes: input.headers.accept) switch input.body { case .none: request.body = nil case let .json(value): @@ -425,15 +354,10 @@ public struct Client: APIProtocol { return .noContent(.init(headers: headers, body: nil)) case 400: let headers: Operations.updatePet.Output.BadRequest.Headers = .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.updatePet.Output.BadRequest.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Operations.updatePet.Output.BadRequest.Body.jsonPayload.self, @@ -460,16 +384,10 @@ public struct Client: APIProtocol { input: input, forOperation: Operations.uploadAvatarForPet.id, serializer: { input in - let path = try converter.renderedRequestPath( - template: "/pets/{}/avatar", - parameters: [input.path.petId] - ) + let path = try converter.renderedPath(template: "/pets/{}/avatar", parameters: [input.path.petId]) var request: OpenAPIRuntime.Request = .init(path: path, method: .put) suppressMutabilityWarning(&request) - converter.setAcceptHeader( - in: &request.headerFields, - contentTypes: input.headers.accept - ) + converter.setAcceptHeader(in: &request.headerFields, contentTypes: input.headers.accept) switch input.body { case let .binary(value): request.body = try converter.setRequiredRequestBodyAsBinary( @@ -484,9 +402,7 @@ public struct Client: APIProtocol { switch response.statusCode { case 200: let headers: Operations.uploadAvatarForPet.Output.Ok.Headers = .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.uploadAvatarForPet.Output.Ok.Body if try contentType == nil || converter.isMatchingContentType( @@ -504,17 +420,11 @@ public struct Client: APIProtocol { } return .ok(.init(headers: headers, body: body)) case 412: - let headers: Operations.uploadAvatarForPet.Output.PreconditionFailed.Headers = - .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let headers: Operations.uploadAvatarForPet.Output.PreconditionFailed.Headers = .init() + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.uploadAvatarForPet.Output.PreconditionFailed.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getResponseBodyAsJSON( Swift.String.self, @@ -526,19 +436,13 @@ public struct Client: APIProtocol { } return .preconditionFailed(.init(headers: headers, body: body)) case 500: - let headers: Operations.uploadAvatarForPet.Output.InternalServerError.Headers = - .init() - let contentType = converter.extractContentTypeIfPresent( - in: response.headerFields - ) + let headers: Operations.uploadAvatarForPet.Output.InternalServerError.Headers = .init() + let contentType = converter.extractContentTypeIfPresent(in: response.headerFields) let body: Operations.uploadAvatarForPet.Output.InternalServerError.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "text/plain" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "text/plain") { - body = try converter.getResponseBodyAsText( + body = try converter.getResponseBodyAsString( Swift.String.self, from: response.body, transforming: { value in .plainText(value) } diff --git a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Server.swift b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Server.swift index 69d4d2e0..ff42f68a 100644 --- a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Server.swift +++ b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Server.swift @@ -85,29 +85,29 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { using: { APIHandler.listPets($0) }, deserializer: { request, metadata in let path: Operations.listPets.Input.Path = .init() let query: Operations.listPets.Input.Query = .init( - limit: try converter.getOptionalQueryItemAsText( - in: metadata.queryParameters, + limit: try converter.getOptionalQueryItemAsURI( + in: request.query, style: .form, explode: true, name: "limit", as: Swift.Int32.self ), - habitat: try converter.getOptionalQueryItemAsText( - in: metadata.queryParameters, + habitat: try converter.getOptionalQueryItemAsURI( + in: request.query, style: .form, explode: true, name: "habitat", as: Operations.listPets.Input.Query.habitatPayload.self ), - feeds: try converter.getOptionalQueryItemAsText( - in: metadata.queryParameters, + feeds: try converter.getOptionalQueryItemAsURI( + in: request.query, style: .form, explode: true, name: "feeds", as: Operations.listPets.Input.Query.feedsPayload.self ), - since: try converter.getOptionalQueryItemAsText( - in: metadata.queryParameters, + since: try converter.getOptionalQueryItemAsURI( + in: request.query, style: .form, explode: true, name: "since", @@ -115,7 +115,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { ) ) let headers: Operations.listPets.Input.Headers = .init( - My_hyphen_Request_hyphen_UUID: try converter.getOptionalHeaderFieldAsText( + My_hyphen_Request_hyphen_UUID: try converter.getOptionalHeaderFieldAsURI( in: request.headerFields, name: "My-Request-UUID", as: Swift.String.self @@ -137,22 +137,19 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressUnusedWarning(value) var response = Response(statusCode: 200) suppressMutabilityWarning(&response) - try converter.setHeaderFieldAsText( + try converter.setHeaderFieldAsURI( in: &response.headerFields, name: "My-Response-UUID", value: value.headers.My_hyphen_Response_hyphen_UUID ) - try converter.setHeaderFieldAsText( + try converter.setHeaderFieldAsURI( in: &response.headerFields, name: "My-Tracing-Header", value: value.headers.My_hyphen_Tracing_hyphen_Header ) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -166,10 +163,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -205,10 +199,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { let contentType = converter.extractContentTypeIfPresent(in: request.headerFields) let body: Operations.createPet.Input.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getRequiredRequestBodyAsJSON( Components.Schemas.CreatePetRequest.self, @@ -239,10 +230,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { ) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -254,17 +242,14 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressUnusedWarning(value) var response = Response(statusCode: statusCode) suppressMutabilityWarning(&response) - try converter.setHeaderFieldAsText( + try converter.setHeaderFieldAsURI( in: &response.headerFields, name: "X-Reason", value: value.headers.X_hyphen_Reason ) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -307,30 +292,21 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, contentType: "application/json; charset=utf-8" ) case let .plainText(value): - try converter.validateAcceptIfPresent( - "text/plain", - in: request.headerFields - ) - response.body = try converter.setResponseBodyAsText( + try converter.validateAcceptIfPresent("text/plain", in: request.headerFields) + response.body = try converter.setResponseBodyAsString( value, headerFields: &response.headerFields, contentType: "text/plain" ) case let .binary(value): - try converter.validateAcceptIfPresent( - "application/octet-stream", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/octet-stream", in: request.headerFields) response.body = try converter.setResponseBodyAsBinary( value, headerFields: &response.headerFields, @@ -358,21 +334,15 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { let contentType = converter.extractContentTypeIfPresent(in: request.headerFields) let body: Operations.postStats.Input.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getRequiredRequestBodyAsJSON( Components.Schemas.PetStats.self, from: request.body, transforming: { value in .json(value) } ) - } else if try converter.isMatchingContentType( - received: contentType, - expectedRaw: "text/plain" - ) { - body = try converter.getRequiredRequestBodyAsText( + } else if try converter.isMatchingContentType(received: contentType, expectedRaw: "text/plain") { + body = try converter.getRequiredRequestBodyAsString( Swift.String.self, from: request.body, transforming: { value in .plainText(value) } @@ -411,9 +381,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { } /// - Remark: HTTP `POST /probe/`. /// - Remark: Generated from `#/paths//probe//post(probe)`. - @available(*, deprecated) func probe(request: Request, metadata: ServerRequestMetadata) - async throws -> Response - { + @available(*, deprecated) func probe(request: Request, metadata: ServerRequestMetadata) async throws -> Response { try await handle( request: request, with: metadata, @@ -423,13 +391,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { let query: Operations.probe.Input.Query = .init() let headers: Operations.probe.Input.Headers = .init() let cookies: Operations.probe.Input.Cookies = .init() - return Operations.probe.Input( - path: path, - query: query, - headers: headers, - cookies: cookies, - body: nil - ) + return Operations.probe.Input(path: path, query: query, headers: headers, cookies: cookies, body: nil) }, serializer: { output, request in switch output { @@ -455,7 +417,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { using: { APIHandler.updatePet($0) }, deserializer: { request, metadata in let path: Operations.updatePet.Input.Path = .init( - petId: try converter.getPathParameterAsText( + petId: try converter.getPathParameterAsURI( in: metadata.pathParameters, name: "petId", as: Swift.Int64.self @@ -469,10 +431,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { let contentType = converter.extractContentTypeIfPresent(in: request.headerFields) let body: Components.RequestBodies.UpdatePetRequest? if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/json" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/json") { body = try converter.getOptionalRequestBodyAsJSON( Components.RequestBodies.UpdatePetRequest.jsonPayload.self, @@ -503,10 +462,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -523,9 +479,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { /// /// - Remark: HTTP `PUT /pets/{petId}/avatar`. /// - Remark: Generated from `#/paths//pets/{petId}/avatar/put(uploadAvatarForPet)`. - func uploadAvatarForPet(request: Request, metadata: ServerRequestMetadata) async throws - -> Response - { + func uploadAvatarForPet(request: Request, metadata: ServerRequestMetadata) async throws -> Response { try await handle( request: request, with: metadata, @@ -533,7 +487,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { using: { APIHandler.uploadAvatarForPet($0) }, deserializer: { request, metadata in let path: Operations.uploadAvatarForPet.Input.Path = .init( - petId: try converter.getPathParameterAsText( + petId: try converter.getPathParameterAsURI( in: metadata.pathParameters, name: "petId", as: Components.Parameters.path_period_petId.self @@ -547,10 +501,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { let contentType = converter.extractContentTypeIfPresent(in: request.headerFields) let body: Operations.uploadAvatarForPet.Input.Body if try contentType == nil - || converter.isMatchingContentType( - received: contentType, - expectedRaw: "application/octet-stream" - ) + || converter.isMatchingContentType(received: contentType, expectedRaw: "application/octet-stream") { body = try converter.getRequiredRequestBodyAsBinary( Foundation.Data.self, @@ -576,10 +527,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .binary(value): - try converter.validateAcceptIfPresent( - "application/octet-stream", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/octet-stream", in: request.headerFields) response.body = try converter.setResponseBodyAsBinary( value, headerFields: &response.headerFields, @@ -593,10 +541,7 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .json(value): - try converter.validateAcceptIfPresent( - "application/json", - in: request.headerFields - ) + try converter.validateAcceptIfPresent("application/json", in: request.headerFields) response.body = try converter.setResponseBodyAsJSON( value, headerFields: &response.headerFields, @@ -610,11 +555,8 @@ fileprivate extension UniversalServer where APIHandler: APIProtocol { suppressMutabilityWarning(&response) switch value.body { case let .plainText(value): - try converter.validateAcceptIfPresent( - "text/plain", - in: request.headerFields - ) - response.body = try converter.setResponseBodyAsText( + try converter.validateAcceptIfPresent("text/plain", in: request.headerFields) + response.body = try converter.setResponseBodyAsString( value, headerFields: &response.headerFields, contentType: "text/plain" diff --git a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Types.swift b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Types.swift index 4beb6da4..3f65c92d 100644 --- a/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Types.swift +++ b/Tests/OpenAPIGeneratorReferenceTests/Resources/ReferenceSources/Petstore_FF_MultipleContentTypes/Types.swift @@ -28,8 +28,7 @@ public protocol APIProtocol: Sendable { func postStats(_ input: Operations.postStats.Input) async throws -> Operations.postStats.Output /// - Remark: HTTP `POST /probe/`. /// - Remark: Generated from `#/paths//probe//post(probe)`. - @available(*, deprecated) func probe(_ input: Operations.probe.Input) async throws - -> Operations.probe.Output + @available(*, deprecated) func probe(_ input: Operations.probe.Input) async throws -> Operations.probe.Output /// Update just a specific property of an existing pet. Nothing is updated if no request body is provided. /// /// - Remark: HTTP `PATCH /pets/{petId}`. @@ -45,9 +44,7 @@ public protocol APIProtocol: Sendable { /// Server URLs defined in the OpenAPI document. public enum Servers { /// Example Petstore implementation service - public static func server1() throws -> URL { - try URL(validatingOpenAPIServerURL: "https://example.com/api") - } + public static func server1() throws -> URL { try URL(validatingOpenAPIServerURL: "https://example.com/api") } public static func server2() throws -> URL { try URL(validatingOpenAPIServerURL: "/api") } } /// Types generated from the components section of the OpenAPI document. @@ -98,10 +95,7 @@ public enum Components { /// Kind of pet /// /// - Remark: Generated from `#/components/schemas/PetKind`. - @frozen - public enum PetKind: String, Codable, Hashable, Sendable, _AutoLosslessStringConvertible, - CaseIterable - { + @frozen public enum PetKind: String, Codable, Hashable, Sendable { case cat = "cat" case dog = "dog" case ELEPHANT = "ELEPHANT" @@ -123,11 +117,7 @@ public enum Components { /// - name: /// - kind: /// - tag: - public init( - name: Swift.String, - kind: Components.Schemas.PetKind? = nil, - tag: Swift.String? = nil - ) { + public init(name: Swift.String, kind: Components.Schemas.PetKind? = nil, tag: Swift.String? = nil) { self.name = name self.kind = kind self.tag = tag @@ -182,10 +172,7 @@ public enum Components { /// - Remark: Generated from `#/components/schemas/PetFeeding`. public struct PetFeeding: Codable, Hashable, Sendable { /// - Remark: Generated from `#/components/schemas/PetFeeding/schedule`. - @frozen - public enum schedulePayload: String, Codable, Hashable, Sendable, - _AutoLosslessStringConvertible, CaseIterable - { + @frozen public enum schedulePayload: String, Codable, Hashable, Sendable { case hourly = "hourly" case daily = "daily" case weekly = "weekly" @@ -196,9 +183,7 @@ public enum Components { /// /// - Parameters: /// - schedule: - public init(schedule: Components.Schemas.PetFeeding.schedulePayload? = nil) { - self.schedule = schedule - } + public init(schedule: Components.Schemas.PetFeeding.schedulePayload? = nil) { self.schedule = schedule } public enum CodingKeys: String, CodingKey { case schedule } } /// - Remark: Generated from `#/components/schemas/DOB`. @@ -232,10 +217,8 @@ public enum Components { /// - Parameters: /// - foo: /// - additionalProperties: A container of undocumented properties. - public init( - foo: Swift.String? = nil, - additionalProperties: OpenAPIRuntime.OpenAPIObjectContainer = .init() - ) { + public init(foo: Swift.String? = nil, additionalProperties: OpenAPIRuntime.OpenAPIObjectContainer = .init()) + { self.foo = foo self.additionalProperties = additionalProperties } @@ -262,10 +245,7 @@ public enum Components { /// - Parameters: /// - foo: /// - additionalProperties: A container of undocumented properties. - public init( - foo: Swift.String? = nil, - additionalProperties: [String: Swift.Int] = .init() - ) { + public init(foo: Swift.String? = nil, additionalProperties: [String: Swift.Int] = .init()) { self.foo = foo self.additionalProperties = additionalProperties } @@ -314,10 +294,7 @@ public enum Components { /// - Parameters: /// - value1: /// - value2: - public init( - value1: Components.Schemas.AllOfObjects.Value1Payload, - value2: Components.Schemas.CodeError - ) { + public init(value1: Components.Schemas.AllOfObjects.Value1Payload, value2: Components.Schemas.CodeError) { self.value1 = value1 self.value2 = value2 } @@ -411,10 +388,7 @@ public enum Components { self = .case4(try .init(from: decoder)) return } catch {} - throw DecodingError.failedToDecodeOneOfSchema( - type: Self.self, - codingPath: decoder.codingPath - ) + throw DecodingError.failedToDecodeOneOfSchema(type: Self.self, codingPath: decoder.codingPath) } public func encode(to encoder: any Encoder) throws { switch self { @@ -508,11 +482,7 @@ public enum Components { case "Walk", "#/components/schemas/Walk": self = .Walk(try .init(from: decoder)) case "MessagedExercise", "#/components/schemas/MessagedExercise": self = .MessagedExercise(try .init(from: decoder)) - default: - throw DecodingError.failedToDecodeOneOfSchema( - type: Self.self, - codingPath: decoder.codingPath - ) + default: throw DecodingError.failedToDecodeOneOfSchema(type: Self.self, codingPath: decoder.codingPath) } } public func encode(to encoder: any Encoder) throws { @@ -526,9 +496,7 @@ public enum Components { @available(*, deprecated) public struct DeprecatedObject: Codable, Hashable, Sendable { /// Creates a new `DeprecatedObject`. public init() {} - public init(from decoder: any Decoder) throws { - try decoder.ensureNoAdditionalProperties(knownKeys: []) - } + public init(from decoder: any Decoder) throws { try decoder.ensureNoAdditionalProperties(knownKeys: []) } } /// - Remark: Generated from `#/components/schemas/ObjectWithDeprecatedProperty`. public struct ObjectWithDeprecatedProperty: Codable, Hashable, Sendable { @@ -620,9 +588,7 @@ public enum Components { /// /// - Parameters: /// - X_hyphen_Reason: A description here. - public init(X_hyphen_Reason: Swift.String? = nil) { - self.X_hyphen_Reason = X_hyphen_Reason - } + public init(X_hyphen_Reason: Swift.String? = nil) { self.X_hyphen_Reason = X_hyphen_Reason } } /// Received HTTP response headers public var headers: Components.Responses.ErrorBadRequest.Headers @@ -691,10 +657,7 @@ public enum Operations { /// - Remark: Generated from `#/paths/pets/GET/query/limit`. public var limit: Swift.Int32? /// - Remark: Generated from `#/paths/pets/GET/query/habitat`. - @frozen - public enum habitatPayload: String, Codable, Hashable, Sendable, - _AutoLosslessStringConvertible, CaseIterable - { + @frozen public enum habitatPayload: String, Codable, Hashable, Sendable { case water = "water" case land = "land" case air = "air" @@ -703,17 +666,13 @@ public enum Operations { /// - Remark: Generated from `#/paths/pets/GET/query/habitat`. public var habitat: Operations.listPets.Input.Query.habitatPayload? /// - Remark: Generated from `#/paths/pets/GET/query/feedsPayload`. - @frozen - public enum feedsPayloadPayload: String, Codable, Hashable, Sendable, - _AutoLosslessStringConvertible, CaseIterable - { + @frozen public enum feedsPayloadPayload: String, Codable, Hashable, Sendable { case omnivore = "omnivore" case carnivore = "carnivore" case herbivore = "herbivore" } /// - Remark: Generated from `#/paths/pets/GET/query/feeds`. - public typealias feedsPayload = [Operations.listPets.Input.Query - .feedsPayloadPayload] + public typealias feedsPayload = [Operations.listPets.Input.Query.feedsPayloadPayload] /// - Remark: Generated from `#/paths/pets/GET/query/feeds`. public var feeds: Operations.listPets.Input.Query.feedsPayload? /// Supply this parameter to filter pets born since the provided date. @@ -746,10 +705,7 @@ public enum Operations { /// /// - Remark: Generated from `#/paths/pets/GET/header/My-Request-UUID`. public var My_hyphen_Request_hyphen_UUID: Swift.String? - public var accept: - [OpenAPIRuntime.AcceptHeaderContentType< - Operations.listPets.AcceptableContentType - >] + public var accept: [OpenAPIRuntime.AcceptHeaderContentType] /// Creates a new `Headers`. /// /// - Parameters: @@ -757,9 +713,8 @@ public enum Operations { /// - accept: public init( My_hyphen_Request_hyphen_UUID: Swift.String? = nil, - accept: [OpenAPIRuntime.AcceptHeaderContentType< - Operations.listPets.AcceptableContentType - >] = .defaultValues() + accept: [OpenAPIRuntime.AcceptHeaderContentType] = + .defaultValues() ) { self.My_hyphen_Request_hyphen_UUID = My_hyphen_Request_hyphen_UUID self.accept = accept @@ -836,10 +791,7 @@ public enum Operations { /// - Parameters: /// - headers: Received HTTP response headers /// - body: Received HTTP response body - public init( - headers: Operations.listPets.Output.Ok.Headers, - body: Operations.listPets.Output.Ok.Body - ) { + public init(headers: Operations.listPets.Output.Ok.Headers, body: Operations.listPets.Output.Ok.Body) { self.headers = headers self.body = body } @@ -928,10 +880,7 @@ public enum Operations { /// /// - Remark: Generated from `#/paths/pets/POST/header/X-Extra-Arguments`. public var X_hyphen_Extra_hyphen_Arguments: Components.Schemas.CodeError? - public var accept: - [OpenAPIRuntime.AcceptHeaderContentType< - Operations.createPet.AcceptableContentType - >] + public var accept: [OpenAPIRuntime.AcceptHeaderContentType] /// Creates a new `Headers`. /// /// - Parameters: @@ -939,9 +888,8 @@ public enum Operations { /// - accept: public init( X_hyphen_Extra_hyphen_Arguments: Components.Schemas.CodeError? = nil, - accept: [OpenAPIRuntime.AcceptHeaderContentType< - Operations.createPet.AcceptableContentType - >] = .defaultValues() + accept: [OpenAPIRuntime.AcceptHeaderContentType] = + .defaultValues() ) { self.X_hyphen_Extra_hyphen_Arguments = X_hyphen_Extra_hyphen_Arguments self.accept = accept @@ -994,9 +942,9 @@ public enum Operations { /// /// - Parameters: /// - X_hyphen_Extra_hyphen_Arguments: A description here. - public init( - X_hyphen_Extra_hyphen_Arguments: Components.Schemas.CodeError? = nil - ) { self.X_hyphen_Extra_hyphen_Arguments = X_hyphen_Extra_hyphen_Arguments } + public init(X_hyphen_Extra_hyphen_Arguments: Components.Schemas.CodeError? = nil) { + self.X_hyphen_Extra_hyphen_Arguments = X_hyphen_Extra_hyphen_Arguments + } } /// Received HTTP response headers public var headers: Operations.createPet.Output.Created.Headers @@ -1074,18 +1022,14 @@ public enum Operations { public var query: Operations.getStats.Input.Query /// - Remark: Generated from `#/paths/pets/stats/GET/header`. public struct Headers: Sendable, Hashable { - public var accept: - [OpenAPIRuntime.AcceptHeaderContentType< - Operations.getStats.AcceptableContentType - >] + public var accept: [OpenAPIRuntime.AcceptHeaderContentType] /// Creates a new `Headers`. /// /// - Parameters: /// - accept: public init( - accept: [OpenAPIRuntime.AcceptHeaderContentType< - Operations.getStats.AcceptableContentType - >] = .defaultValues() + accept: [OpenAPIRuntime.AcceptHeaderContentType] = + .defaultValues() ) { self.accept = accept } } public var headers: Operations.getStats.Input.Headers @@ -1407,18 +1351,14 @@ public enum Operations { public var query: Operations.updatePet.Input.Query /// - Remark: Generated from `#/paths/pets/{petId}/PATCH/header`. public struct Headers: Sendable, Hashable { - public var accept: - [OpenAPIRuntime.AcceptHeaderContentType< - Operations.updatePet.AcceptableContentType - >] + public var accept: [OpenAPIRuntime.AcceptHeaderContentType] /// Creates a new `Headers`. /// /// - Parameters: /// - accept: public init( - accept: [OpenAPIRuntime.AcceptHeaderContentType< - Operations.updatePet.AcceptableContentType - >] = .defaultValues() + accept: [OpenAPIRuntime.AcceptHeaderContentType] = + .defaultValues() ) { self.accept = accept } } public var headers: Operations.updatePet.Input.Headers @@ -1580,9 +1520,7 @@ public enum Operations { /// - Remark: Generated from `#/paths/pets/{petId}/avatar/PUT/header`. public struct Headers: Sendable, Hashable { public var accept: - [OpenAPIRuntime.AcceptHeaderContentType< - Operations.uploadAvatarForPet.AcceptableContentType - >] + [OpenAPIRuntime.AcceptHeaderContentType] /// Creates a new `Headers`. /// /// - Parameters: @@ -1684,8 +1622,7 @@ public enum Operations { /// - headers: Received HTTP response headers /// - body: Received HTTP response body public init( - headers: Operations.uploadAvatarForPet.Output.PreconditionFailed.Headers = - .init(), + headers: Operations.uploadAvatarForPet.Output.PreconditionFailed.Headers = .init(), body: Operations.uploadAvatarForPet.Output.PreconditionFailed.Body ) { self.headers = headers @@ -1719,8 +1656,7 @@ public enum Operations { /// - headers: Received HTTP response headers /// - body: Received HTTP response body public init( - headers: Operations.uploadAvatarForPet.Output.InternalServerError.Headers = - .init(), + headers: Operations.uploadAvatarForPet.Output.InternalServerError.Headers = .init(), body: Operations.uploadAvatarForPet.Output.InternalServerError.Body ) { self.headers = headers diff --git a/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift b/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift index 45beede8..ef1fc33f 100644 --- a/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift +++ b/Tests/OpenAPIGeneratorReferenceTests/SnippetBasedReferenceTests.swift @@ -773,7 +773,7 @@ final class SnippetBasedReferenceTests: XCTestCase { public enum Schemas { @frozen public enum MyEnum: RawRepresentable, Codable, Hashable, Sendable, - _AutoLosslessStringConvertible, CaseIterable + CaseIterable { case one case _empty @@ -821,9 +821,7 @@ final class SnippetBasedReferenceTests: XCTestCase { """ public enum Schemas { @frozen - public enum MyEnum: String, Codable, Hashable, Sendable, - _AutoLosslessStringConvertible, CaseIterable - { + public enum MyEnum: String, Codable, Hashable, Sendable { case one = "one" case _empty = "" case _tart = "$tart" @@ -851,9 +849,7 @@ final class SnippetBasedReferenceTests: XCTestCase { public enum Schemas { public struct MyOpenEnum: Codable, Hashable, Sendable { @frozen - public enum Value1Payload: String, Codable, Hashable, Sendable, - _AutoLosslessStringConvertible, CaseIterable - { + public enum Value1Payload: String, Codable, Hashable, Sendable { case one = "one" case two = "two" } @@ -1487,24 +1483,24 @@ final class SnippetBasedReferenceTests: XCTestCase { } """, client: """ - { input in let path = try converter.renderedRequestPath(template: "/foo", parameters: []) + { input in let path = try converter.renderedPath(template: "/foo", parameters: []) var request: OpenAPIRuntime.Request = .init(path: path, method: .get) suppressMutabilityWarning(&request) - try converter.setQueryItemAsText( + try converter.setQueryItemAsURI( in: &request, style: .form, explode: true, name: "single", value: input.query.single ) - try converter.setQueryItemAsText( + try converter.setQueryItemAsURI( in: &request, style: .form, explode: true, name: "manyExploded", value: input.query.manyExploded ) - try converter.setQueryItemAsText( + try converter.setQueryItemAsURI( in: &request, style: .form, explode: false, @@ -1517,22 +1513,22 @@ final class SnippetBasedReferenceTests: XCTestCase { server: """ { request, metadata in let path: Operations.get_foo.Input.Path = .init() let query: Operations.get_foo.Input.Query = .init( - single: try converter.getOptionalQueryItemAsText( - in: metadata.queryParameters, + single: try converter.getOptionalQueryItemAsURI( + in: request.query, style: .form, explode: true, name: "single", as: Swift.String.self ), - manyExploded: try converter.getOptionalQueryItemAsText( - in: metadata.queryParameters, + manyExploded: try converter.getOptionalQueryItemAsURI( + in: request.query, style: .form, explode: true, name: "manyExploded", as: [Swift.String].self ), - manyUnexploded: try converter.getOptionalQueryItemAsText( - in: metadata.queryParameters, + manyUnexploded: try converter.getOptionalQueryItemAsURI( + in: request.query, style: .form, explode: false, name: "manyUnexploded", diff --git a/Tests/PetstoreConsumerTests/Test_Client.swift b/Tests/PetstoreConsumerTests/Test_Client.swift index 96bfe271..b40b16a7 100644 --- a/Tests/PetstoreConsumerTests/Test_Client.swift +++ b/Tests/PetstoreConsumerTests/Test_Client.swift @@ -38,7 +38,7 @@ final class Test_Client: XCTestCase { XCTAssertEqual(request.path, "/pets") XCTAssertEqual( request.query, - "limit=24&habitat=water&feeds=herbivore&feeds=carnivore&since=2023-01-18T10:04:11Z" + "limit=24&habitat=water&feeds=herbivore&feeds=carnivore&since=2023-01-18T10%3A04%3A11Z" ) XCTAssertEqual(baseURL.absoluteString, "/api") XCTAssertEqual(request.method, .get) diff --git a/Tests/PetstoreConsumerTests/Test_Server.swift b/Tests/PetstoreConsumerTests/Test_Server.swift index 485bfcd3..b253df9c 100644 --- a/Tests/PetstoreConsumerTests/Test_Server.swift +++ b/Tests/PetstoreConsumerTests/Test_Server.swift @@ -54,20 +54,13 @@ final class Test_Server: XCTestCase { let response = try await server.listPets( .init( path: "/api/pets", + query: "limit=24&habitat=water&feeds=carnivore&feeds=herbivore&since=\(Date.testString)", method: .get, headerFields: [ .init(name: "My-Request-UUID", value: "abcd-1234") ] ), - .init( - queryParameters: [ - .init(name: "limit", value: "24"), - .init(name: "habitat", value: "water"), - .init(name: "feeds", value: "carnivore"), - .init(name: "feeds", value: "herbivore"), - .init(name: "since", value: Date.testString), - ] - ) + .init() ) XCTAssertEqual(response.statusCode, 200) XCTAssertEqual( @@ -218,7 +211,7 @@ final class Test_Server: XCTestCase { XCTAssertEqual( response.headerFields, [ - .init(name: "X-Reason", value: "bad luck"), + .init(name: "X-Reason", value: "bad%20luck"), .init(name: "content-type", value: "application/json; charset=utf-8"), ] )