top of page

Codable: Ignore casing while decoding Enum values


A cat looking in a mean way at a laptop

How many times have your QA reached out to you saying that the app is “randomly” crashing, only for you to debug and find out that backend sent you fruit and not Fruit for type of food item; not sweet :(

Consider the same example as of our previous article :

This outputs the following:

Ohhh I love some Tea

But what if we change favouriteBeverage in the JSON data from Tea to tea (we just change the casing of the enum case: Tea) ?

__lldb_expr_3/MyPlayground.playground:67: Fatal error: ‘try!’ expression unexpectedly raised an error: Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: “favouriteBeverage”, intValue: nil)], debugDescription: “Cannot initialize Beverage from invalid String value tea”, underlyingError: nil))

Focus on the part of the message: Cannot initialize Beverage from invalid String value tea

If it was an actual app instead of a playground code, the app would have crashed. So how do we ignore the case while decoding our enum such that our app should be able to handle it instead of outright crashing?

One of the ways, and my personal favourite: Case Insensitive Raw Value



We will make use of a protocol for this purpose: CaseInsensitiveRawValue

What the above code(one that belongs to decoder) essentially does is the following:

  • Fetches the value from the container

  • First, it tries to create the enum as-is from the value

  • If above fails, then it iterates through the cases of the enum and tries to match it to each value while ignoring the casing. If one matches, then it assigns the same to the enum

  • Even after ignoring the casing, if there is no match (which can only happen if the provided value is incorrect), it throws a type-mismatch exception

Alongside providing a custom decoder, we have also added a custom initialiserthat will do the same thing in case we want to use the same mechanism for manually initialising an enum rather than via decoder

Just make sure that whenever you’re initialing the enum using a String raw value, you have to use Beverage(caseInsensitiveRawValue:) and not Beverage(rawValue:)

The overall code will now look like below:

The above code will output the following:

Ohhh I love some Tea

Bonus

This will work fine for values that have different casing from the ones specified inside the enum.

But what if we give it a different value, say juice as favouriteBeverage which is not defined inside the Beverage enum? Answer: It’ll crash

If you’ve read my previous article, you’re aware that we can handle invalid values inside enum while decoding it

Codable: Handling Incorrect Enum Values

Safeguarding Your Codebase: Dealing with Unanticipated Enum Values

What if we could combine both of them ( CaseInsensitiveRawValue and IncorrectEnumFallbackMechanism ) into one that can handle:

  • Different casing of value than the ones specified inside the enum

  • Different value than the ones specified inside the enum



Behold: CaseInsensitiveRawValueWithIncorrectFallbackMechanism

(I know, I know. The name is Hysteria-rrifying)

This will take care of both the situations specified above. The combined overall code will now look like this:

The above code will output the following:

Wait! What is that?

… instead of crashing like earlier

There might be other ways out there but like I said, this is my favorite!

That’s it, folks! Happy Coding!

Site's author picture

Shubham Bakshi

Been coding since '13. Rode the Apple bandwagon in '18. Some can say it was love at first byte. I engineer apps with such finesse, they practically dance through your device. And if you're a dev feeling lost in the code jungle, fear not! I'm here to be your coding compass, guiding you through the wilderness of curly braces and semicolons.

Website logo
© Bits & Bytes w/ Bakshi. All rights reserved.
bottom of page