Skip to content

[BUG][Swift] Decimal-Decoding not working #13410

@Feuerwerk

Description

@Feuerwerk
Description

I have a service providing a list of objects with a property of type string and format number (BigDecimal on the backend side). The generated service description is fine:

"minValue": {
  "type": "string",
  "format": "number"
}

The models generated by OpenAPI-Generator also looks good:

public var minValue: Decimal?

But when my swift5 client tries to consume this service I always get the exception that the returning data is not valid and can't be decoded.
I checked the data transmitted from the server and it looks valid to me.

"minValue": "0.12345"

When sending data from the swift client to the server, it will encode the decimal as a number

"value": 0.12345
openapi-generator version

6.1.0

Generation Details

openapi-generator generate -i http://localhost:8081/v3/api-docs -g swift5 -c config.json

{
	"unwrapRequired" : true,
	"projectName" : "ApiClient",
	"podAuthors" : "XXXXX",
	"podHomepage" : "XXXX",
	"podSummary" : "Summary"
}
Suggest a fix

I can fix the problem when I add the following four methods to the generated Extensions.swift

extension KeyedEncodingContainerProtocol {
    mutating func encode(_ value: Decimal, forKey key: Self.Key) throws {
        var mutableValue = value
        let stringValue = NSDecimalString(&mutableValue, Locale(identifier: "en_US"))
        try encode(stringValue, forKey: key)
    }
    
    mutating func encodeIfPresent(_ value: Decimal?, forKey key: Self.Key) throws {
        if let value = value {
            try encode(value, forKey: key)
        }
    }
}

extension KeyedDecodingContainerProtocol {
    func decode(_ type: Decimal.Type, forKey key: Self.Key) throws -> Decimal {
        let stringValue = try decode(String.self, forKey: key)
        guard let decimalValue = Decimal(string: stringValue) else {
            let context = DecodingError.Context(codingPath: [key], debugDescription: "The key \(key) couldn't be converted to a Decimal value")
            throw DecodingError.typeMismatch(type, context)
        }
        return decimalValue
    }
    
    func decodeIfPresent(_ type: Decimal.Type, forKey key: Self.Key) throws -> Decimal? {
        guard let stringValue = try decodeIfPresent(String.self, forKey: key) else {
            return nil
        }
        guard let decimalValue = Decimal(string: stringValue) else {
            let context = DecodingError.Context(codingPath: [key], debugDescription: "The key \(key) couldn't be converted to a Decimal value")
            throw DecodingError.typeMismatch(type, context)
        }
        return decimalValue
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions