Skip to main content

Adding Support for Optional and Nullable Fields in a Model in Python SDKs

· 5 min read

In the improved Python SDK, fields of a custom type can now differentiate between a nullable value and a missing value and will operate according to the behavior of the type specified. This way you can either pass a value that corresponds to the type specified, use null as a value or skip the field altogether depending upon the defined behavior of the field.

Details

We are delighted to announce support for optional and nullable fields within custom types in Python SDKs. Fields of custom type can be marked as nullable and optional based on what the intended behavior is for that particular field.

A property marked as optional means that the user can either pass the value that conforms with the type specified or can skip that value altogether. Whereas, if a field is marked as nullable, then the user can either pass the value that corresponds to the type defined or use a nullable value. Other combinations are also possible using this flag, which will be discussed later in the changelog.

What was Supported Before?

Previously, the Python SDK didn't support optional or nullable flags for the fields of a model. Both these flags were equally treated, meaning if either one of the flags was true for any field of a model, it would be treated as a nullable value. Hence null value was accepted in either case.

What has Changed?

Functionality of fields within custom type

Now the latest Python SDK respects the Optional and Nullable settings in their true form. The table below shows how the optional and nullable settings affect the serialization of different values:

Nullable = trueNullable = false
Optional = true
  • Key can be ignored
  • key can have null as value
  • Key can have a valid value
{}, {"key":value}, {"key:null}
  • Key can be ignored
  • Key cannot have null as value
{}, {"key":value}
Optional = false (required)
  • Key cannot be ignored
  • Key can have null as value
{"key":value}, {"key":null}
  • Key cannot be ignored
  • Key cannot have null value
{"key":value}
  • Optional means that if no value is provided, then it should be ignored during serialization.
  • Non-Optional (required) means that the key has to be included in JSON irrespective of the value.
  • Nullable means that value of the key can be null.
  • Non-Nullable means that value of the key cannot be null.

Current changed behavior in Python

  • Optional = true, Nullable = true An uninitialized field will be ignored in JSON during serialization. And if a proper value is assigned, then it will not be ignored.

  • Optional = true, Nullable = false An uninitialized field will be ignored in JSON during serialization. And if a proper value is assigned, then it is not ignored. A nullable value will throw an error.

  • Optional = false, Nullable = true Field must be included in JSON representation and it can have null its value.

  • Optional = false, Nullable = false Field must be included in JSON representation and it cannot have null as a value. In case of a missing or null value, an exception will be thrown.

  • Changes in Oneof and Anyof Model fields Another noticeable change introduced is the support for optional and nullable fields with custom types using oneOf and anyOf keywords. For example, if a value of a field can be one of the custom types Morning or Evening, then the Python SDK should accept either of the two incoming values exactly matching one of the schemas. However, if a field is marked as both optional and nullable, then this means:

  • An incoming null value is acceptable because the nullable flag is true

  • Field could be missing altogether because the optional flag is true

This is how the API specification looks like for the example explained in APIMatic format:

{
"Name": "SimpleCase",
"ImplementationType": "Structure",
"Description": "This class contains simple case of oneOf.",
"Fields": [
{
"Optional": true,
"OneOfTypes": [
{
"Type": "Morning",
"IsSdlNativeType": false,
"Constant": false,
"DefaultValue": "",
"Nullable": false,
"IsArray": false,
"IsMap": false,
"IsArrayOfMap": false
},
{
"Type": "Evening",
"IsSdlNativeType": false,
"Constant": false,
"DefaultValue": "",
"Nullable": false,
"IsArray": false,
"IsMap": false,
"IsArrayOfMap": false
}
],
"Type": "Object",
"IsSdlNativeType": true,
"Constant": false,
"IsStream": false,
"IsAttribute": false,
"Attributes": {},
"Nullable": true,
"IsArray": false,
"IsMap": false,
"IsArrayOfMap": false,
"Deprecated": false,
"Name": "session",
"Description": "Course session",
"DefaultValue": ""
}
],
"Deprecated": false
}

The accepted values for this schema are:

{
"session": {
"startsAt": "startsAt9",
"endsAt": "endsAt9",
"offerLunch": true
}
}

Or:

{
"session": {
"startsAt": "startsAt9",
"endsAt": "endsAt9",
"offerDinner": true
}
}

Or:

{  "session": null
}

Or, in case the optional field is missing:

{ }

Changes in Deserialization of Custom Types

The support for optional and nullable settings has also changed the behavior of how the fields of a custom type are deserialized into their respective types. Previously, optional and nullable properties were treated in a similar manner. This means that if a value for a certain field was missing, it would automatically be initialed with the value None. And if a nullable value was missing, it would also be initialized as None. However with the latest changes, if an optional field's value is missing, that property will not be initialized in the model.