Skip to content

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.