@@ -4225,6 +4225,199 @@ final class SnippetBasedReferenceTests: XCTestCase {
4225
4225
)
4226
4226
}
4227
4227
4228
+ func testRequestMultipartBodyReferencedSchemaRecursive( ) throws {
4229
+ try self . assertRequestInTypesClientServerTranslation (
4230
+ """
4231
+ /foo:
4232
+ post:
4233
+ requestBody:
4234
+ required: true
4235
+ content:
4236
+ multipart/form-data:
4237
+ schema:
4238
+ $ref: '#/components/schemas/NodeWrapper'
4239
+ responses:
4240
+ default:
4241
+ description: Response
4242
+ """ ,
4243
+ """
4244
+ schemas:
4245
+ NodeWrapper:
4246
+ type: object
4247
+ properties:
4248
+ node:
4249
+ $ref: '#/components/schemas/Node'
4250
+ Node:
4251
+ type: object
4252
+ properties:
4253
+ parent:
4254
+ $ref: '#/components/schemas/Node'
4255
+ """ ,
4256
+ input: """
4257
+ public struct Input: Sendable, Hashable {
4258
+ @frozen public enum Body: Sendable, Hashable {
4259
+ case multipartForm(OpenAPIRuntime.MultipartBody<Components.Schemas.NodeWrapper>)
4260
+ }
4261
+ public var body: Operations.post_sol_foo.Input.Body
4262
+ public init(body: Operations.post_sol_foo.Input.Body) {
4263
+ self.body = body
4264
+ }
4265
+ }
4266
+ """ ,
4267
+ schemas: """
4268
+ public enum Schemas {
4269
+ @frozen public enum NodeWrapper: Sendable, Hashable {
4270
+ public struct nodePayload: Sendable, Hashable {
4271
+ public var body: Components.Schemas.Node
4272
+ public init(body: Components.Schemas.Node) {
4273
+ self.body = body
4274
+ }
4275
+ }
4276
+ case node(OpenAPIRuntime.MultipartPart<Components.Schemas.NodeWrapper.nodePayload>)
4277
+ case undocumented(OpenAPIRuntime.MultipartRawPart)
4278
+ }
4279
+ public struct Node: Codable, Hashable, Sendable {
4280
+ public var parent: Components.Schemas.Node? {
4281
+ get {
4282
+ self.storage.value.parent
4283
+ }
4284
+ _modify {
4285
+ yield &self.storage.value.parent
4286
+ }
4287
+ }
4288
+ public init(parent: Components.Schemas.Node? = nil) {
4289
+ self.storage = .init(value: .init(parent: parent))
4290
+ }
4291
+ public enum CodingKeys: String, CodingKey {
4292
+ case parent
4293
+ }
4294
+ public init(from decoder: any Decoder) throws {
4295
+ self.storage = try .init(from: decoder)
4296
+ }
4297
+ public func encode(to encoder: any Encoder) throws {
4298
+ try self.storage.encode(to: encoder)
4299
+ }
4300
+ private var storage: OpenAPIRuntime.CopyOnWriteBox<Storage>
4301
+ private struct Storage: Codable, Hashable, Sendable {
4302
+ var parent: Components.Schemas.Node?
4303
+ init(parent: Components.Schemas.Node? = nil) {
4304
+ self.parent = parent
4305
+ }
4306
+ typealias CodingKeys = Components.Schemas.Node.CodingKeys
4307
+ }
4308
+ }
4309
+ }
4310
+ """ ,
4311
+ client: """
4312
+ { input in
4313
+ let path = try converter.renderedPath(
4314
+ template: " /foo " ,
4315
+ parameters: []
4316
+ )
4317
+ var request: HTTPTypes.HTTPRequest = .init(
4318
+ soar_path: path,
4319
+ method: .post
4320
+ )
4321
+ suppressMutabilityWarning(&request)
4322
+ let body: OpenAPIRuntime.HTTPBody?
4323
+ switch input.body {
4324
+ case let .multipartForm(value):
4325
+ body = try converter.setRequiredRequestBodyAsMultipart(
4326
+ value,
4327
+ headerFields: &request.headerFields,
4328
+ contentType: " multipart/form-data " ,
4329
+ allowsUnknownParts: true,
4330
+ requiredExactlyOncePartNames: [],
4331
+ requiredAtLeastOncePartNames: [],
4332
+ atMostOncePartNames: [
4333
+ " node "
4334
+ ],
4335
+ zeroOrMoreTimesPartNames: [],
4336
+ encoding: { part in
4337
+ switch part {
4338
+ case let .node(wrapped):
4339
+ var headerFields: HTTPTypes.HTTPFields = .init()
4340
+ let value = wrapped.payload
4341
+ let body = try converter.setRequiredRequestBodyAsJSON(
4342
+ value.body,
4343
+ headerFields: &headerFields,
4344
+ contentType: " application/json; charset=utf-8 "
4345
+ )
4346
+ return .init(
4347
+ name: " node " ,
4348
+ filename: wrapped.filename,
4349
+ headerFields: headerFields,
4350
+ body: body
4351
+ )
4352
+ case let .undocumented(value):
4353
+ return value
4354
+ }
4355
+ }
4356
+ )
4357
+ }
4358
+ return (request, body)
4359
+ }
4360
+ """ ,
4361
+ server: """
4362
+ { request, requestBody, metadata in
4363
+ let contentType = converter.extractContentTypeIfPresent(in: request.headerFields)
4364
+ let body: Operations.post_sol_foo.Input.Body
4365
+ let chosenContentType = try converter.bestContentType(
4366
+ received: contentType,
4367
+ options: [
4368
+ " multipart/form-data "
4369
+ ]
4370
+ )
4371
+ switch chosenContentType {
4372
+ case " multipart/form-data " :
4373
+ body = try converter.getRequiredRequestBodyAsMultipart(
4374
+ OpenAPIRuntime.MultipartBody<Components.Schemas.NodeWrapper>.self,
4375
+ from: requestBody,
4376
+ transforming: { value in
4377
+ .multipartForm(value)
4378
+ },
4379
+ boundary: contentType.requiredBoundary(),
4380
+ allowsUnknownParts: true,
4381
+ requiredExactlyOncePartNames: [],
4382
+ requiredAtLeastOncePartNames: [],
4383
+ atMostOncePartNames: [
4384
+ " node "
4385
+ ],
4386
+ zeroOrMoreTimesPartNames: [],
4387
+ decoding: { part in
4388
+ let headerFields = part.headerFields
4389
+ let (name, filename) = try converter.extractContentDispositionNameAndFilename(in: headerFields)
4390
+ switch name {
4391
+ case " node " :
4392
+ try converter.verifyContentTypeIfPresent(
4393
+ in: headerFields,
4394
+ matches: " application/json "
4395
+ )
4396
+ let body = try await converter.getRequiredRequestBodyAsJSON(
4397
+ Components.Schemas.Node.self,
4398
+ from: part.body,
4399
+ transforming: {
4400
+ $0
4401
+ }
4402
+ )
4403
+ return .node(.init(
4404
+ payload: .init(body: body),
4405
+ filename: filename
4406
+ ))
4407
+ default:
4408
+ return .undocumented(part)
4409
+ }
4410
+ }
4411
+ )
4412
+ default:
4413
+ preconditionFailure( " bestContentType chose an invalid content type. " )
4414
+ }
4415
+ return Operations.post_sol_foo.Input(body: body)
4416
+ }
4417
+ """
4418
+ )
4419
+ }
4420
+
4228
4421
func testRequestMultipartBodyReferencedSchemaWithEncoding( ) throws {
4229
4422
try self . assertRequestInTypesClientServerTranslation (
4230
4423
"""
0 commit comments