Microsoft Graph Developer Tip: What is unknownFutureValue, and how to opt-in to the latest possible data
I came across this information looking for something else, but it answered a question I had, and I’ve not seen it explained before so I thought it was worthwhile bringing it to your attention.
In the Microsoft Graph REST API, many of the enum properties contain a value unknownFutureValue. I was always a bit confused by this: firstly, why include it unless you know something is going to be there, and why only one value? What happens if there are 2 unknown future values? Here’s an example of this, taken from the teamSpecialization enum (an optional property on a team):
It turns out that using unknownFutureValue like this is actually an established pattern in Microsoft Graph, and now it’s explained on the Best Practices page.
It’s referred to as a “sentinel value” – which I had to look up. This denotes a value that acts as a termination point for looping algorithms rather than a ‘real value’. It’s used to denote the “end” of all the real values.
Why add a sentinel value at all? It’s to allow for future values to be added that won’t then break any existing applications. Remember that Microsoft Graph is used by millions of people, and the v1.0 endpoints are designed to be slow-changing: “Updates to APIs on this endpoint are additive in nature and do not break existing app scenarios.”
Having a sentinel value lets Microsoft add additional enums over time that weren’t on the original list, without worrying that they will break existing functionality because when they come to be served through the API, the API will only serve up enum values up to and including the sentinel value – the “known values”. Newer values (“unknown values”) are given a higher index value than the sentinel to differentiate them.
So, can I see these exciting new unknown values?
Yes, you can! If you want to opt-in to receiving not only the “known” enum values but also additional values that have been added since you can indicate this to Graph when you make your requests by including a special header:
This HTTP header indicates to Graph to include any unknown values in the response.
If you do decide to use this then you need to ensure that your application will be able to handle an enum that might suddenly add a value one day without notice and have a way to deal with that.
What happens to data with a property that includes an unknown value?
Let’s imagine that a new enum value gets added to the teamSpecialization enum, and then one or more teams are assigned this enum value. What happens if an API call requests this team (and doesn’t have the Prefer header set). What will the enum value be?
I need to test this out to be sure, but here’s what I think. I don’t think it will be the actual new enum value that’s returned as a property of the team because that risks breaking clients that aren’t expecting an enum value they don’t know about.
Instead, I imagine that either the team with the enum is not returned at all, or if it is then it’s the sentinel value that’s used on that property- the unknownFutureValue enum. This is a “safe” default to use because it’s expected, even though it’s not actually the true enum value.
Real-world example: Chat Message messageType
You can see an evolvable enum in action today in Graph: the messageType enum of a Chat Message. This enum has 4 “known values”: message, chatEvent, typing & unknownFutureValue.
It also has an “unknown value” – systemEventMessage but you won’t see this unless you use the Prefer header.
Use by exception, unless you’ve designed for it
I don’t think you should go and add this header to all your Graph calls tomorrow, because it’s quite likely your code makes assumptions that enums won’t just change without warning, and any internal mapping to objects, condition statements etc might break. However, for specific properties where you suspect (or have been told) additional enums may exist then it’s worth trying. You could also consider evolving your code to handle the concept of evolvable enums everywhere without error and then consider opting in for all calls. Maybe. 🙂