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!

Related Posts

Comments


bottom of page