JSONOneOf
Specify a record that needs to be serialized or deserialized.
Syntax
JSONOneOf
is an optional attribute.
Usage
You can set JSONOneOf
on a record, elements of a record, or a user-defined type to specify elements that need to be serialized or
deserialized. For example, if you have complex data or data that is flexible in how it may be
represented, then you can define the data with a number of schemas and JSONOneOf
to
validate against exactly one of the schemas at runtime.
There are considerations for working with primitive
types in schemas to avoid ambiguity in the oneOf
validation. When defining
schemas for JSONOneOf
, keep in mind what happens with the conversion of BDL types
to JSON types. For more information on conversion mapping for Genero BDL data types to JSON, go to
OpenAPI types mapping: BDL.
The deserialization error -15807 is returned at runtime if there are more than one of the following types in the schema:
STRING
STRING format: DATE/DATETIME
BOOLEAN
INTEGER
NUMBER
In this example there is an INTEGER
and a DECIMAL
, but the JSON
schema will convert DECIMAL
to NUMBER
; therefore, this schema is
allowed.
PUBLIC TYPE integerNumber RECORD ATTRIBUTE(JSONOneOf)
_selector SMALLINT ATTRIBUTE(JSONSelector),
i INTEGER,
fl DECIMAL
END RECORD
PUBLIC TYPE primType RECORD ATTRIBUTE(JSONOneOf)
_selector SMALLINT ATTRIBUTE(JSONSelector),
a STRING,
b STRING
END RECORD
INTEGER
,
TINYINT
, SMALLINT
, and BIGINT
, to
INTEGER
. PUBLIC TYPE primNumberType RECORD ATTRIBUTE(JSONOneOf)
_selector SMALLINT ATTRIBUTE(JSONSelector),
i INTEGER,
ty TINYINT,
si SMALLINT,
i2 BIGINT
END RECORD
DATETIME YEAR TO SECOND
is converted to a
STRING
with a specific format in JSON (format: date-time
);
therefore, this type is allowed. However, if both STRING
values are valid for
JSONOneOf
, the priority is given to the DATETIME YEAR TO SECOND
value. A special rule is implemented to resolve this conflict. For details, go to Special rulesPUBLIC TYPE stringDatetime RECORD ATTRIBUTE(JSONOneOf)
_selector SMALLINT ATTRIBUTE(JSONSelector),
a STRING,
da DATETIME YEAR TO SECOND
END RECORD
Special rules
oneOf
validation , special rules have to be applied to resolve potential
conflicts involving the STRING
/DATE
/DATETIME
and
INTEGER
/NUMBER
types. This occurs when the value sent is valid for
both types and the JSON schema cannot resolve oneOf
. To resolve this conflict, a
priority selection applies in the following cases:- If there is a valid
STRING
and aDATE/DATETIME
, theDATE/DATETIME
will have priority. - If there is a valid
INTEGER
and aNUMBER
, theINTEGER
will have priority.
DATE/DATETIME
over STRING
is applied with different values, study the examples shown in Table 1, Table 2, and Table 3.To understand how the priority of INTEGER
over NUMBER
is
applied with different values, study the examples shown in Table 4, Table 5, and Table 6
Before applying the priority rule (shown in the Priority column), deserialization for the value is checked first, and this is shown in the column Deserialization. The Result column shows the resolution applied.
Type | Deserialization | Priority | Result |
---|---|---|---|
DATETIME |
YES | YES | DATETIME |
STRING |
YES | NO |
Type | Deserialization | Priority | Result |
---|---|---|---|
DATE |
NO | YES | STRING |
STRING |
YES | NO |
Type | Deserialization | Priority | Result |
---|---|---|---|
DATETIME |
NO | YES | STRING |
STRING |
YES | NO |
Type | Deserialization | Priority | Result |
---|---|---|---|
INTEGER |
YES | YES | INTEGER |
NUMBER |
YES | NO |
Type | Deserialization | Priority | Result |
---|---|---|---|
INTEGER |
YES | YES | INTEGER |
NUMBER |
YES | NO |
Type | Deserialization | Priority | Result |
---|---|---|---|
INTEGER |
NO | YES | NUMBER |
NUMBER |
YES | NO |
The JSONOneOf
attribute represents the oneOf
keyword in the
JSON schema property of the Swagger and OpenAPI specification.
The JSONOneOf
attribute must be used in combination with the JSONSelector attribute.
Example 1: using JSONOneOf
In this example, the JSONOneOf
attribute is set on the input record of the
CreateAccount
function. At a request to the
service, you can choose which member of the createAccountType
record –
id
or name
– to use by setting the member of the input record with
the JSONSelector
attribute, _selector
in our example, to the index value of the record member.
For example, in a request from your client application, you
might have a statement like this: LET in._SELECTOR=2
.
In the CreateAccount
function, the CASE
statement tests for the _selector
value.
IMPORT COM
PUBLIC TYPE accountType RECORD
id INTEGER,
name STRING,
date DATETIME YEAR TO SECOND,
age INTEGER,
gender BOOLEAN
END RECORD
PRIVATE DEFINE accounts DYNAMIC ARRAY OF accountType
PUBLIC DEFINE accountError RECORD ATTRIBUTE(WSError = 'account service error')
id INTEGER,
msg STRING
END RECORD
TYPE createAccountType RECORD ATTRIBUTE(JSONOneOf)
_selector INTEGER ATTRIBUTE(JSONSelector),
id INTEGER,
name STRING
END RECORD
FUNCTION CreateAccount(
in createAccountType)
ATTRIBUTE(WSPost, WSPath = "/createaccount")
RETURNS(createAccountType)
DEFINE out createAccountType
DEFINE idx INTEGER
LET out = in
CASE
WHEN in._selector = 1
LET idx = accounts.search("id", in.id)
IF idx > 0 THEN
# raise RESTError with accountError
ELSE
CALL accounts.appendElement()
LET accounts[accounts.getLength()].id = in.id
END IF
WHEN in._selector = 2
LET idx = accounts.search("name", in.name)
# ... function code ...
END CASE
RETURN out
END FUNCTION
In the OpenAPI documentation, the GWS engine exposes the oneOf
property in the
schema
for the record elements defined with JSONOneOf
. In the
following sample schema, a request to the operation to create an account can choose to send the
record for the id or name.
Example 2: using JSONOneOf with JSONRequired
In this example, the use of the JSONRequired
attribute in addition to the
JSONOneOf
attribute is important to validate the schemas. In the
complexType
record, there are three sub-records. Each sub-record also has a member
set with the JSONRequired
attribute. The effect of this required member is that it
allows the schemas to be validated.
In JSON schema, there is a default to allowing additional properties – properties
that do not correspond to any property name – which has the effect of allowing schemas to be
validated with any properties. Therefore, in our example (with JSONOneOf
alone) no
schema could be validated, since they would all be valid. For an example using
JSONOneOf
and JSONAdditionalProperties
instead of
JSONRequired
, go to JSONAdditionalProperties.
With JSONRequired
in the validation process, the JSON schema checks that the
required property has been received; otherwise, the schema will be invalid and will be eliminated.
In the end, according to the oneOf
requirement, there must remain only one valid
schema in all the possible schemas.
For more information on properties and additional properties, go to the JSON Schema (external link) object page and search for additional properties.
# In this example, a property with attribute JSONRequired is mandatory
# Otherwise, all schemas will be valid and oneOf can only accept one valid schema
TYPE complexType RECORD ATTRIBUTE(JSONOneOf)
_selector INTEGER ATTRIBUTE(JSONSelector),
accountById RECORD
id INTEGER ATTRIBUTE(JSONRequired),
birthday DATE,
gender BOOLEAN
END RECORD,
accountByname RECORD
name STRING ATTRIBUTE(JSONRequired),
birthday DATE,
gender BOOLEAN
END RECORD,
accountBydate RECORD
date DATETIME YEAR TO SECOND ATTRIBUTE(JSONRequired),
birthday DATE,
gender BOOLEAN
END RECORD
END RECORD
FUNCTION echoComplexType(
in complexType)
ATTRIBUTE(WSPost, WSPath = "/echoComplexType")
RETURNS(complexType)
DEFINE out complexType
LET out = in
DISPLAY out._selector
CASE
WHEN out._selector == 2
DISPLAY "This is the schema 1 with id required property: ",
out.accountById.id
WHEN out._selector == 3
DISPLAY "This is the schema 2 with STRING value: ",
out.accountByName.name
WHEN out._selector == 4
DISPLAY "This is the schema 3 with DATE value: ",
out.accountBydate.date
END CASE
RETURN out
END FUNCTION
In the OpenAPI documentation, the GWS creates the JSON schema with oneOf
and
required
properties.