Tool: Structurize is the JSON Structure-focused command-line interface and conversion toolkit from the Avrotize project.

[13.405, 52.52] is a JSON array, but the array does not identify its positions. It does not say whether longitude or latitude comes first, or whether the numbers are coordinates at all.

In JSON Structure, properties defines the names and types of the positions. tuple lists those names in wire order. The instance remains an array.

A point with named positions

The schema below defines a WGS 84 geographic point. The coordinate reference system is stated in the type name and description here; the core tuple mechanism itself is about structure, not geodesy.

{
  "$schema": "https://json-structure.org/meta/core/v0/#",
  "$id": "https://example.com/schemas/wgs84-position",
  "name": "Wgs84Position",
  "type": "object",
  "description": "An observation position using WGS 84 longitude and latitude.",
  "properties": {
    "stationId": { "type": "string" },
    "position": {
      "name": "GeographicPoint",
      "type": "tuple",
      "description": "Longitude followed by latitude, in decimal degrees.",
      "properties": {
        "longitude": { "type": "double" },
        "latitude": { "type": "double" }
      },
      "tuple": ["longitude", "latitude"]
    }
  },
  "required": ["stationId", "position"],
  "additionalProperties": false
}

Its JSON instance remains an array:

{
  "$schema": "https://example.com/schemas/wgs84-position",
  "stationId": "berlin-alexanderplatz",
  "position": [13.405, 52.52]
}

The first number is longitude because longitude is first in tuple. Its schema is the property named longitude. The second number is latitude for the same reason.

Swap the names in the tuple array and you change the wire contract. Swap only

Generated code keeps the names

The Structurize TypeScript generator maps the tuple to a class with named properties:

structurize s2ts wgs84-position.struct.json --out generated/typescript

For the GeographicPoint tuple above, it generates this class:

/** Longitude followed by latitude, in decimal degrees. */
export class GeographicPoint {
    constructor(
        public longitude: number,
    public latitude: number
    ) {}

    public toJSON(): [number, number] {
        return [this.longitude, this.latitude];
    }

    public static fromJSON(json: string): GeographicPoint {
        const value: unknown = JSON.parse(json);
        if (!Array.isArray(value) || value.length !== 2) {
            throw new Error('Expected a GeographicPoint JSON array with 2 elements');
        }
        return new GeographicPoint(
            value[0] as number,
          value[1] as number
        );
    }
}

Application code therefore reads point.longitude and point.latitude. JSON.stringify(point) calls toJSON() and emits [13.405,52.52], preserving the tuple’s positional wire contract. GeographicPoint.fromJSON() performs the reverse mapping from the JSON array to the named properties. the two instance values and the JSON remains structurally valid, because both positions are doubles, but the point moves. A schema cannot detect a plausible number placed in the wrong same-typed position. Naming the positions makes the contract reviewable and lets generated APIs use domain names instead of item0 and item1.

The length is fixed

Every property declared by a tuple is implicitly required. Every declared property name must appear in the tuple array, whose order defines the instance positions. The resulting array therefore has the tuple’s exact length.

That means this is invalid:

{
  "$schema": "https://example.com/schemas/wgs84-position",
  "stationId": "berlin-alexanderplatz",
  "position": [13.405]
}

So is [13.405, 52.52, 34.0]. There is no suggested prefix followed by an open-ended tail. The named property schemas determine every position and the array’s length.

There is no required keyword inside the tuple. That keyword belongs to objects, while tuple positions are required by the tuple definition itself. Adding required would not clarify the model; it would violate the core rule that permits required only on object schemas.

When an object is the better shape

An object would be clearer on the wire:

{
  "longitude": 13.405,
  "latitude": 52.52
}

Use that shape when readers should see the names on the wire. Choose the tuple when an existing format is positional, when measured payload or storage cost justifies the positional form, or when an external contract demands coordinate arrays. The schema and generated code retain names either way.

How Other Schema Systems Model Positional Data

JSON Schema Draft 2020-12 models positional arrays with prefixItems. Each position gets a schema, but the positions themselves have no standard names. Titles or descriptions can annotate them, yet those annotations do not create property identities for language mappings.

Avro records name fields but encode them according to the selected Avro binary or JSON encoding; Avro arrays, by contrast, have one item schema rather than a fixed heterogeneous position list. A two-coordinate Avro record is therefore the natural named model, but its JSON encoding is not this bare array.

XML Schema can define an ordered sequence of named child elements. That retains names on the wire, which is closer to a JSON object than to [13.405, 52.52].

JSON Structure combines the property identities of a record with the wire shape of an array. For a geographic coordinate pair whose representation cannot change, that permits named APIs without changing the JSON.

GeographicPoint and its description document WGS 84, but core does not make that reference machine-resolvable. When a processor must identify and check the reference system rather than trust prose, the semantic annotations extension provides coordinateReferenceSystem. Position names prevent a longitude and latitude from becoming anonymous numbers; they cannot tell a processor which geodetic datum those numbers use.