How to decode enums ignoring case in Swift Codable

⋅ 3 min read ⋅ Swift Development Enum

Table of Contents

Swift makes it is effortless to decode Enums from its raw value. All you need to do are make sure your enum is raw representable enum, e.g., can be represented by Int or String, and that your enum conforms to Codable protocol.

Here is a struct and enum ready for encoding/decoding.

enum UserType: String, Codable {
case member
case guest
}

struct User: Codable {
let type: UserType
let name: String
}

I recently had a chance to work with a legacy inconsistent API where enums can be represented in both uppercase and lowercase 😢. I will show you how to do case insensitive enum decoding in this article.

I hope you work on consistent API and don't need to do this customization, but I think you can take something out of this and apply it elsewhere.

Raw representable enums Codable behavior

Raw representable enums are the type that can be converted to and from an associated raw value. In our previous example, UserType can be converted to and from a string.

Each case is converted to and from its raw value. In our case, .member converted from "member" and .guest converted from "guest".

Here is an example where we decode a user of type .member.

let jsonString = """
{
"type": "member",
"name": "Sarunw"
}
"""

let jsonData = jsonString.data(using: .utf8)!

let user = try! JSONDecoder().decode(User.self, from: jsonData)

print(user.name)
// Sarunw
print(user.type)
// member

The default behavior for enums decoding is case-sensitive comparison, meaning "MEMBER" and "Member" will fail our decoding.

You will get a fatal error when trying to decode the following JSON string.

{
"type": "Member",
"name": "Sarunw"
}

You will get the following error which dictates that our UserType is initialized using an invalid string.

Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "type", intValue: nil)], debugDescription: "Cannot initialize UserType from invalid String value Member", underlyingError: nil))

How to make case insensitive Codable enum

To make our Codable enum support case-insensitive raw value, we need to come up with our own implementation of Decodable's initializer.

We make the change to UserType by opt-out from Decodable default implementation of init(from: Decoder).

enum UserType: String, Codable {
case member
case guest

init(from decoder: Decoder) throws {
// 1
let container = try decoder.singleValueContainer()
// 2
let rawString = try container.decode(String.self)

// 3
if let userType = UserType(rawValue: rawString.lowercased()) {
self = userType
} else {
// 4
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Cannot initialize UserType from invalid String value \(rawString)")
}
}
}

1 We use try decoder.singleValueContainer() here instead of try decoder.container(keyedBy: CodingKeys.self) that we normally use because what get parse to enum is single nonkeyed value (in this case, a string).
2 We decode it by specifying an expected decoded type.
3 This is where our main logic is located. We ignore the case by converting a passing string to lowercase before using it to initialize UserType.
4 If it failed, we throw the same error that we got from the default implementation.

With these changes, our enum can decode an enum ignoring the case.


Read more article about Swift, Development, Enum, or see all available topic

Enjoy the read?

If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Buy me a coffee Tweet Share
Previous
How to disable dark mode in iOS

If you are not ready to make your app support dark mode, you can opt-out of that. You can do disable it for an entire app or partially. Learn different ways to disable dark mode in iOS.

Next
What is a variant in SF Symbols

iOS introduces a new concept to SF Symbols, SymbolVariants. Let's see how this improves the way we interact with symbols.

← Home