Inside Data Structure of API Responses, Variables of Enum Type should be Nullable

This article is a quick and straightforward note for API compat that introduces how we made a mistake when we can’t easily extend our initial API response.

Bram Yeh
2 min readOct 14, 2019

Imagine that we have an API which replies the product’s shipping and payments’ types:

{
"id": 7512115,
"shipping": {
"type": 2,
"value": "3"
},
"payments":[
1,
2,
3,
5
]
}

We might simply define the following data structure for this API response. We didn’t add @Nullable because there must be ShippingType type and others inside API responses.

public class Product {
public String id;
public Shipping shipping;
public List<Payment> Payments;
}
public class Shipping {
public ShippingType type;
public String value;
}
public enum ShippingType {
@SerializedName("0")
NORMAL,
@SerializedName("1")
PREORDER,
@SerializedName("2")
CUSTOMMADE,
@SerializedName("3")
SELFBOOK
}
public enum Payment {
@SerializedName(value = "1")
ATM,
@SerializedName(value = "2")
CREDIT_CARD,
@SerializedName(value = "3")
LINE_PAY,
@SerializedName(value = "4")
APPLE_PAY,
@SerializedName(value = "5")
GOOGLE_PAY
}

It works well until this API has a new type of “4”, which didn’t support in original ShippingType, so we might think it’s easy to modify.

public enum ShippingType {
@SerializedName("0")
NORMAL,
@SerializedName("1")
PREORDER,
@SerializedName("2")
CUSTOMMADE,
@SerializedName("3")
SELFBOOK,
@SerializedName("4")
FAST

}

Yes, this is correct implementation, but only the new version of the app. The previous version might crash because it didn’t recognize “4”, so it will have ShippingType type of a null value. It quickly causes a RuntimeException, for example,

if (product == null || product.shipping == null) {
return;
}
switch(product.shipping.type) {
case NORMAL:
// TODO
case PREORDER:
// TODO
case CUSTOMMADE:
// TODO
case SELFBOOK:
// TODO
default:
// DO NOTHING
}

It will crash at switch(product.shipping.type) because type is null and switch will try to get type’s enum ordinal().

List<Payment> Payments might also occur crash when new payment type from API, but the app didn’t define either. In this case, the Payments list will contain a null element, and then we easily forget to verify, especially on foreach.

There are so many scenarios to improve this implementation, for example, add the annotation

public class Shipping {
@Nullable public ShippingType type;
@NonNull public String value;
}

So you won’t forget to verify type before switch. Or you can use Kotlin

data class Shipping (
val type : ShippingType?
val value : String
)

Gson will write unknown enum values as null — ignoring the Kotlin nullability — since the Java reflection doesn’t know about Kotlin. Make such values nullable and handle them as deserialization errors or use Moshi which will do it automatically.

https://arturdryomov.online/posts/kotlin-enum-recipes/

The most important is that, when using Enum for API responses, we have to make our app work even new value it cannot recognize in the further.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Bram Yeh
Bram Yeh

Written by Bram Yeh

Lead Android & iOS Mobile Engineer at Yahoo (Verizon Media) Taiwan https://www.linkedin.com/in/hanruyeh/

No responses yet

Write a response