JSON Input
For ease of integration, Scowl allows clients to post data in a flexible JSON format. Every topology includes a schema, which specifies how payload data is extracted into typed variables.
JSON Path Basics
To extract a value, specify a JSONPath (which starts with a $
) along with the field's type, using the as
keyword:
amount := $.item.amount as float
This definition will extract a float value from a JSON payload like the following:
{
"_type": "purchase",
"item": {
"amount": 8.99,
"sku": "..."
}
}
By default, all inputs are required. Sumatra will throw a run-time error if the JSON path is missing or the value is null. The feature's value will be set to null
.
Optional Inputs
To specify an input as optional, use the ?
syntax:
amount := $.item.amount as float?
Now, in the case null or missing input, no run-time error will be thrown. The value of amount
will be null
as before.
Default Values
To provide a default value for an optional input, add a literal after the ?
:
amount := $.item.amount as float ? 0.0
Note that input features cannot depend on other features, so the following is not allowed:
-- not allowed
amount := $.item.amount as float ? another_feature
Coercion and Errors
Scowl will make its best effort to coerce data into the desired variable type. Coercion that fails or truncates data will throw an error.
The following table details the return value and error on example inputs:
$ | $.foo as int | $.foo as int? | $.foo as int ? 0 |
---|---|---|---|
{"foo": 5} |
5 | 5 | 5 |
{"foo": "5"} |
5 | 5 | 5 |
{"foo": 5.0} |
5 | 5 | 5 |
{"foo": 5.6} |
5 (error: loss of precision) | 5 (error: loss of precision) | 5 (error: loss of precision) |
{"foo": null} |
null (error: required input is null) | null | 0 |
{"foo": "null"} |
null (error: required input is null) | null | 0 |
{} |
null (error: required input missing) | null | 0 |
{"foo": "bar"} |
null (error: expected int) | null (error: expected int) | 0 (error: expected int) |
Note
For a string
input, a value of "null"
is treated as the missing value, null
.
Complex Data Types
Scowl supports structs, maps, and arrays as JSON input types, including nesting of these complex types.
Structs, Maps, Arrays
Consider the following JSON:
{
"shapes": {
"triangle": {
"sides": 3,
"types": ["equilateral", "isosceles", "scalene"]
},
"quadrilateral": {
"sides": 4,
"types": ["square", "rectangle", "rhombus", "trapezoid", "parallelogram"]
}
}
}
We can extract the entire data structure with the following Scowl code:
shapes := $.shapes as map{string: {sides: int, types: [string]}}
The result is a map that contains a struct that contains an array.
Missing Values
Every type in a complex type may be specified as optional. Further, every primitive type within the complex type may be given a default value.
$.foo as [int?] -- required; nullable elements
In the above, $foo
is a required array input. Null values within the array will remain null with no error thrown.
$.foo as [int]? -- optional; non-null elements
In the above, $.foo
is now optional and will become null
without error if missing. However, every element of the array must be a non-null integer, or else an error is thrown.
$.foo as [int?]? -- optional; nullable elements
The above combines the two. Elements of the array may be null or the entire array may be missing.
Finally, nested primitive types may have default values:
$.shapes as map{string: {sides: int ? 0, types: [string ? ""]?}}?
Advanced JSON Path
Scowl supports some of the more advanced JSONPath statements, such as extracting specific keys from a list:
For example, for the following JSON:
{
"books": [
{
"author": "Weir, Andy",
"title": "Project Hail Mary"
},
{
"author": "Pressfield, Steven",
"title": "Gates of Fire"
}
]
}
this JSON path:
$.books[*].author as [string]
returns:
["Weir, Andy", "Pressfield, Steven"]
More details and example queries can be found in the JSONPath documentation.