Closed agattringer closed 1 month ago
Hi @agattringer, I'd like to be able to reproduce it - can you provide the full operation, so including the responses
key, please?
Oh I see the issue - your body is not marked as required: true
, so it will be skipped. The generator emits a warning, which you should see in Xcode/in build output. After you add the missing required key, it'll show up.
The specification explicitly states that a request multipart body must be required, and never optional. Can you check if that fixes your issue?
Thank you very much for your quick answer!
required: true
actually fixes the issue.
Great! 🙏
Hey @agattringer, how did you initialize body for your multipart request? Can you check if my schema and generated code satisfies everything neccessary for upload? I'm going in circles and obiously missing something.
schema:
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
description: 'The image file. Max size: 64 MB, Min dimensions: 640x640'
format: binary
required: true
code:
@frozen internal enum Body: Sendable, Hashable {
/// - Remark: Generated from `#/paths/accounts/{account}/content/basic/image/upload/POST/requestBody/multipartForm`.
@frozen internal enum multipartFormPayload: Sendable, Hashable {
/// - Remark: Generated from `#/paths/accounts/{account}/content/basic/image/upload/POST/requestBody/multipartForm/file`.
internal struct filePayload: Sendable, Hashable {
internal var body: OpenAPIRuntime.HTTPBody
/// Creates a new `filePayload`.
///
/// - Parameters:
/// - body:
internal init(body: OpenAPIRuntime.HTTPBody) {
self.body = body
}
}
case file(OpenAPIRuntime.MultipartPart<Operations.post_sol_accounts_sol__lcub_account_rcub__sol_content_sol_basic_sol_image_sol_upload.Input.Body.multipartFormPayload.filePayload>)
case undocumented(OpenAPIRuntime.MultipartRawPart)
}
/// - Remark: Generated from `#/paths/accounts/{account}/content/basic/image/upload/POST/requestBody/content/multipart\/form-data`.
case multipartForm(OpenAPIRuntime.MultipartBody<Operations.post_sol_accounts_sol__lcub_account_rcub__sol_content_sol_basic_sol_image_sol_upload.Input.Body.multipartFormPayload>)
}
@erikhric It looks correct to me.
You should be able to initialize the Body with the multipartBody case. What error are you hitting?
Problem is obviously me, not the generator - I failed to find example for uploading an image. I don't know how to initialize Input for upload operation:
func uploadImage(accountId: Int, imageData: Data) {
//this gives error Initializer 'init(_:)' requires the types 'Operations.post_sol_accounts_sol__lcub_account_rcub__sol_content_sol_basic_sol_image_sol_upload.Input.Body.multipartFormPayload' and 'Data.Element' (aka 'UInt8') be equivalent
let multi: MultipartBody<Operations.post_sol_accounts_sol__lcub_account_rcub__sol_content_sol_basic_sol_image_sol_upload.Input.Body.multipartFormPayload> = .init(imageData)
// Cannot convert value of type 'MultipartBody<Operations.post_sol_accounts_sol__lcub_account_rcub__sol_content_sol_basic_sol_image_sol_upload.Input.Body.multipartFormPayload>.Type' to expected argument type 'MultipartBody<Operations.post_sol_accounts_sol__lcub_account_rcub__sol_content_sol_basic_sol_image_sol_upload.Input.Body.multipartFormPayload>'
let input: Operations.post_sol_accounts_sol__lcub_account_rcub__sol_content_sol_basic_sol_image_sol_upload
.Input = .init(path: .init(account: accountId),
body: .multipartForm(MultipartBody<Operations.post_sol_accounts_sol__lcub_account_rcub__sol_content_sol_basic_sol_image_sol_upload.Input.Body.multipartFormPayload>))
}
@erikhric check out the last example here: https://github.com/apple/swift-openapi-generator/blob/main/Examples/various-content-types-client-example/Sources/ContentTypesClient/ContentTypesClient.swift
A multipart body can be initialized using an array of parts. Each of the parts is named after the part name in the OpenAPI document. The part value can then be the image data itself.
I get Cannot convert value of type 'Data' to expected argument type 'HTTPBody'
error when passing image data.
If I convert it to string
let stringData = String(decoding: imageData, as: UTF8.self)
let multi: MultipartBody<Operations.post_sol_accounts_sol__lcub_account_rcub__sol_content_sol_basic_sol_image_sol_upload.Input.Body.multipartFormPayload> = [
.file(.init(payload: .init(body: stringData), filename: "image")) //Cannot convert value of type 'String' to expected argument type 'HTTPBody'
]
It only works directly with string in place
.file(.init(payload: .init(body: "this works, or at least it compiles"), filename: "image"))
You can create an HTTPBody value from data using let httpBody = HTTPBody(data)
.
@czechboy0 thank you! I'll be in Prague next month, can I buy you a beer? 🍺 😅
Question
Hello! I do have a problem with code generation it seems.
My open API spec file contains this section:
For some reason the generated client method
processPurchase()
does not have abody
input parameter. So I cannot pass the data properly into the POST method. Code generation works as expected for all other parts of the spec.Am I doing something wrong here or is this an issue with the generator?