Description
Motivation
I want to be able de generate client and server from an OpenAPI specification, for an API which use XML as content type for request and response body.
Currently, application/xml
contents for request and response are not generated by swift-openapi-generator
, and only OpenAPIRuntime.HTTPBody
enum associated value is available for xml content.
A Workaround is to use an external XML encoder and decoder, like CoreOffice XMLCoder, and make the encoding from / decoding to HTTPBody
.
struct Credentials: Encodable {
var username: String
var password_hash: String
}
struct Token: Decodable {
var token: String
}
let credentials = Credentials(username: "johnapplessed", password_hash: "d2hhdCBkaWQgeW91IGV4cGVjdD8=")
let encoder = XMLEncoder()
let encoded = try encoder.encode(credentials)
let response = try await client.authenticate(body: .xml(HTTPBody(encoded)))
let xmlBody = try response.ok.body.xml
let xmlData = try await Data(collecting: xmlBody, upTo: .max)
let decoder = XMLDecoder()
let decoded = try decoder.decode(Token.self, from: xmlData)
let token = decoded.token
Proposed solution
One quick solution could be to implement a new CodingStrategy
for xml in swift-openapi-generator
.
For swift-openapi-runtime
, we could add the following methods to Converter
:
Client/server | Set/get | Schema location | Coding strategy | Optional/required | Method name |
---|---|---|---|---|---|
client | set | request body | XML | optional | setOptionalRequestBodyAsXML |
client | set | request body | XML | required | setRequiredRequestBodyAsXML |
client | get | response body | XML | required | getResponseBodyAsXML |
server | get | request body | XML | optional | getOptionalRequestBodyAsXML |
server | get | request body | XML | required | getRequiredRequestBodyAsXML |
server | set | response body | XML | required | setResponseBodyAsXML |
Encoding / Decoding logic can be implemented into these methods, with an XML encoder / decoder.
As Converter
have encoder
and decoder
properties as type JSONEncoder
and JSONDecoder
, we could:
- Rename
encoder
tojsonEncoder
anddecoder
tojsonDecoder
, and instantiate axmlEncoder
andxmlDecoder
inConverter
init. - Instantiate a
XMLEncoder
orXMLDecoder
in call of methods above.
Example:
extension Converter {
public func setRequiredRequestBodyAsXML<T: Encodable>(
_ value: T,
headerFields: inout HTTPFields,
contentType: String
) throws -> HTTPBody {
try setRequiredRequestBody(
value,
headerFields: &headerFields,
contentType: contentType,
convert: convertBodyCodableToXML
)
}
}
Alternatives considered
I found that Converter
struct is not suited for adding support of new content type. With the proposed solution, the Converter
struct will have types of <#HTTPMediaType#>Encoder
and <#HTTPMediaType#>Decoder
, while not necessarily needed.
For XML only API, Converter
still need a JSONEncoder
and JSONDecoder
.
I thought that, maybe, and I would like to have your opinion on this, we must implement a Converter
for a specific http media type, like Vapor is doing with ContentEncoder
and ContentDecoder
. Each http media type would be assigned to a specific Converter.
What's your thoughts about this?
Additional information
No response
Activity
czechboy0 commentedon Mar 28, 2024
Hi @ugocottin,
yes XML is officially supported by the OpenAPI specification, so it'd be reasonable for us to support it here.
Since we already generate
Codable
types, I think the main piece of work would be to create anXMLEncoder
andXMLDecoder
that can work withCodable
types, and then we can update the generator.Once that's in place, your plan above with extending the
Converter
, adding aCodingStrategy
is exactly right.A heads up - this would need to be contributed by you, and we'd help steer the code through pull request review.
If that sounds good, go ahead! 🙏
czechboy0 commentedon Mar 28, 2024
Oh I missed that you already linked to such encoder/decoder in https://github.com/CoreOffice/XMLCoder.
The only concern there is that it's a dependency that isn't API-stable.
I wonder if we could somehow offer this as explicitly opt-in, where only adopters who want XML would include that dependency.
Maybe some new optional conversion methods on
OpenAPIRuntime.Configuration
, able to convert betweenHTTPBody
andCodable
using a custom encoder/decoder.ugocottin commentedon Apr 2, 2024
Hello @czechboy0
Thanks for the feedback. I've submitted a first pull request to apple/swift-openapi-runtime#102.
As you suggested, I added the possibility to define custom encoding / decoding behaviour through
OpenAPIRuntime.Configuration
, withCustomCoder
protocol.Thanks!
czechboy0 commentedon Apr 2, 2024
Looks good - feel free to open a PR for the generator as well (even if it won't pass until the runtime change lands and is released), it's easier to review both changes together.
Add support for application/xml body (#102)
czechboy0 commentedon Apr 16, 2024
Ok @ugocottin, the runtime changes landed in swift-openapi-runtime 1.4.0, so please bump the dependency of the generator's Package.swift and you should be able to finish the generator work.
7 remaining items