yonaskolb / SwagGen

OpenAPI/Swagger 3.0 Parser and Swift code generator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Floating point precision issues with JSONSerialization

jrcmramos opened this issue · comments

This issue happens during the (de)serialisation of JSON content while working with floating point types. When defining a number property in the OpenAPI spec, the same number will not be internalised and serialised to the same value using the default JSONEncoder and JSONDecoder. Here is an example:

import Cocoa

struct PayloadEx: Codable {
    let value: Double?
    
    enum CodingKeys: String, CodingKey {
        case value
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        value = try values.decodeIfPresent(.value)
    }
}

extension KeyedDecodingContainer {
    func decodeIfPresent<T>(_ key: KeyedDecodingContainer.Key) throws -> T? where T: Decodable {
        return try decodeIfPresent(T.self, forKey: key)
    }
}

let payload = """
{
  "value": 5.02
}
"""

let payloadData = payload.data(using: .utf8)

let decoder = JSONDecoder()
let model = try decoder.decode(PayloadEx.self, from: payloadData!)

print(model.value) // Optional(5.02)

let jsonEncoder = JSONEncoder()

print(String(decoding: try! jsonEncoder.encode(model), as: UTF8.self)) // {"value":5.0199999809265137}

This issue is related and better described in this bug report https://bugs.swift.org/browse/SR-7054?page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel .
However this is not a problem related with the implementation of the framework, we will most likely have issues in case we are using CRUD API endpoints making use of number properties.

Our current solution implements a new Encoder class that (as described in one of the solutions of the above mentioned ticket) converts the Double to Decimal and then encodes it.

This PR should help with adding your own Encoder #203

Closing this for now. Let me know @jrcmramos if that doesn't work