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