Skip to content

Level Payload Validation

This document describes the validation rules applied to the Level GeoJSON payloads in the system. The validation is performed in two layers:

  1. JSON Schema Validation: Structural and field-level constraints.
  2. Runtime Validation: Business rules and contextual consistency enforced by application logic.
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://geojson.org/schema/Level.json",
  "title": "GeoJSON Level",
  "type": "object",
  "required": [
    "type",
    "features"
  ],
  "properties": {
    "type": {
      "type": "string",
      "enum": [
        "FeatureCollection"
      ]
    },
    "features": {
      "type": "array",
      "items": {
        "title": "GeoJSON Level",
        "type": "object",
        "required": [
          "type",
          "properties",
          "geometry"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "id": {
            "type": "number"
          },
          "properties": {
            "type": "object",
            "required": [
              "fid",
              "lvl",
              "typeCode",
              "name",
              "sid",
              "bid",
              "shortName"
            ],
            "properties": {
              "fid": {
                "type": "string",
                "maxLength": 36,
                "minLength": 1
              },
              "name": {
                "type": "string",
                "maxLength": 255,
                "minLength": 0
              },
              "typeCode": {
                "type": "string",
                "enum": [
                  "level-outline"
                ]
              },
              "lvl": {
                "type": "number"
              },
              "sid": {
                "type": "string"
              },
              "bid": {
                "type": "string"
              },
              "shortName": {
                "type": "string"
              }
            }
          },
          "geometry": {
            "oneOf": [
              {
                "title": "GeoJSON Polygon",
                "type": "object",
                "required": ["type", "coordinates"],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": ["Polygon"]
                  },
                  "coordinates": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "array",
                      "minItems": 4,
                      "items": {
                        "type": "array",
                        "minItems": 2,
                        "items": [
                          {
                            "type": "number",
                            "multipleOf": 0.00000001,
                            "exclusiveMinimum": -180,
                            "exclusiveMaximum": 180
                          },
                          {
                            "type": "number",
                            "multipleOf": 0.00000001,
                            "exclusiveMinimum": -90,
                            "exclusiveMaximum": 90
                          }
                        ]
                      }
                    }
                  },
                  "bbox": {
                    "type": "array",
                    "minItems": 4,
                    "items": {
                      "type": "number"
                    }
                  }
                }
              },
              {
                "title": "GeoJSON MultiPolygon",
                "type": "object",
                "required": ["type", "coordinates"],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": ["MultiPolygon"]
                  },
                  "coordinates": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "array",
                        "minItems": 4,
                        "items": {
                          "type": "array",
                          "minItems": 2,
                          "items": [
                            {
                              "type": "number",
                              "multipleOf": 0.00000001,
                              "exclusiveMinimum": -180,
                              "exclusiveMaximum": 180
                            },
                            {
                              "type": "number",
                              "multipleOf": 0.00000001,
                              "exclusiveMinimum": -90,
                              "exclusiveMaximum": 90
                            }
                          ]
                        }
                      }
                    }
                  },
                  "bbox": {
                    "type": "array",
                    "minItems": 4,
                    "items": {
                      "type": "number"
                    }
                  }
                }
              }
            ]
          },
          "bbox": {
            "type": "array",
            "minItems": 4,
            "items": {
              "type": "number"
            }
          }
        }
      }
    },
    "bbox": {
      "type": "array",
      "minItems": 4,
      "items": {
        "type": "number"
      }
    }
  }
}

1. JSON Schema Validation

The JSON payload must conform to the GeoJSON FeatureCollection structure, where each item in the features array represents a single level of a building.

🔸 Root Object

  • type: "FeatureCollection" (required)
  • features: array of Feature objects (required)
  • bbox: optional array of numbers (minItems: 4)

🔸 features[].type

  • Must be "Feature" (required)

🔸 features[].id

  • Optional numeric identifier

🔸 features[].properties

  • Must include the following fields (required):
    • fid: string (1–36 chars)
    • lvl: number
    • typeCode: must be "level-outline"
    • name: string (max 255 chars)
    • sid: string
    • bid: string
    • shortName: string

🔸 features[].geometry

  • Must be either a valid GeoJSON Polygon or MultiPolygon
  • Coordinates must:

    • Conform to valid GeoJSON structure.
    • Include at least 4 coordinate points for each ring.
    • Have latitude (lat) in range (-90, 90) and longitude (lon) in range (-180, 180), with high precision.
  • Optional bbox field must be an array of at least 4 numbers.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://geojson.org/schema/Level.json",
  "title": "GeoJSON Level",
  "type": "object",
  "required": [
    "type",
    "properties",
    "geometry"
  ],
  "properties": {
    "type": {
      "type": "string",
      "enum": [
        "Feature"
      ]
    },
    "id": {
      "type": "number"
    },
    "properties": {
      "type": "object",
      "required": [
        "fid",
        "lvl",
        "typeCode",
        "name",
        "sid",
        "bid",
        "shortName"
      ],
      "properties": {
        "fid": {
          "type": "string",
          "maxLength": 36,
          "minLength": 1
        },
        "name": {
          "type": "string",
          "maxLength": 255,
          "minLength": 0
        },
        "typeCode": {
          "type": "string",
          "enum": [
            "level-outline"
          ]
        },
        "lvl": {
          "type": "number"
        },
        "sid": {
          "type": "string"
        },
        "bid": {
          "type": "string"
        },
        "shortName": {
          "type": "string"
        }
      }
    },
    "geometry": {
      "oneOf": [
        {
          "title": "GeoJSON Polygon",
          "type": "object",
          "required": ["type", "coordinates"],
          "properties": {
            "type": {
              "type": "string",
              "enum": ["Polygon"]
            },
            "coordinates": {
              "type": "array",
              "minItems": 1,
              "items": {
                "type": "array",
                "minItems": 4,
                "items": {
                  "type": "array",
                  "minItems": 2,
                  "items": [
                    {
                      "type": "number",
                      "multipleOf": 0.00000001,
                      "exclusiveMinimum": -180,
                      "exclusiveMaximum": 180
                    },
                    {
                      "type": "number",
                      "multipleOf": 0.00000001,
                      "exclusiveMinimum": -90,
                      "exclusiveMaximum": 90
                    }
                  ]
                }
              }
            },
            "bbox": {
              "type": "array",
              "minItems": 4,
              "items": {
                "type": "number"
              }
            }
          }
        },
        {
          "title": "GeoJSON MultiPolygon",
          "type": "object",
          "required": ["type", "coordinates"],
          "properties": {
            "type": {
              "type": "string",
              "enum": ["MultiPolygon"]
            },
            "coordinates": {
              "type": "array",
              "minItems": 1,
              "items": {
                "type": "array",
                "items": {
                  "type": "array",
                  "minItems": 4,
                  "items": {
                    "type": "array",
                    "minItems": 2,
                    "items": [
                      {
                        "type": "number",
                        "multipleOf": 0.00000001,
                        "exclusiveMinimum": -180,
                        "exclusiveMaximum": 180
                      },
                      {
                        "type": "number",
                        "multipleOf": 0.00000001,
                        "exclusiveMinimum": -90,
                        "exclusiveMaximum": 90
                      }
                    ]
                  }
                }
              }
            },
            "bbox": {
              "type": "array",
              "minItems": 4,
              "items": {
                "type": "number"
              }
            }
          }
        }
      ]
    },
    "bbox": {
      "type": "array",
      "minItems": 4,
      "items": {
        "type": "number"
      }
    }
  }
}

1. JSON Schema Validation

The incoming payload must conform to the following rules defined in the JSON Schema:

🔸 Root Object

  • type: must be "Feature" (required).
  • id: optional numeric identifier.
  • bbox: optional array with at least 4 numerical values.

🔸 properties Object

  • fid (Feature Identifier):

    • Required
    • String
    • Minimum length: 1
    • Maximum length: 36
  • lvl:

    • Required
    • Integer
  • typeCode:

    • Required
    • Must be "level-outline"
  • name:

    • Required
    • String
    • Maximum length: 255
  • sid (Feature Identifier):

    • Required
    • String
    • Minimum length: 1
    • Maximum length: 36
  • bid (Feature Identifier):

    • Required
    • String
    • Minimum length: 1
    • Maximum length: 36
  • shortName:

    • Required
    • String
    • Maximum length: 255
  • Other fields are allowed unless explicitly forbidden (see Runtime Validation section).

🔸 geometry Object

  • Must be a valid GeoJSON Polygon or MultiPolygon object.
  • Coordinates must:

    • Conform to valid GeoJSON structure.
    • Include at least 4 coordinate points for each ring.
    • Have latitude (lat) in range (-90, 90) and longitude (lon) in range (-180, 180), with high precision.
  • Optional bbox field must be an array of at least 4 numbers.


2. Runtime Validations (Application Logic)

These checks are performed in application code and cannot be enforced by JSON Schema alone:

🔹 1. fid (Feature Identifier)

  • If missing:
    → "fid is required."
  • If invalid:
    → "The fid field contains an invalid value."

🔹 2. sid (Site Identifier)

  • If missing:
    → "sid is required. fid: '{fid}'"
  • If invalid:
    → "The sid field contains an invalid value."
  • If not matching the requested site:
    → "The requested siteIdentifier and payload sid do not match. fid : '{fid}'"

🔹 3. bid (Building Identifier)

  • If missing:
    → "bid is required. fid: '{fid}'"
  • If invalid:
    → "The bid field contains an invalid value."
  • If not matching the requested building:
    → "The requested buildingIdentifier and payload bid do not match. fid : '{fid}'"

🔹 4. name

  • Cannot be null or empty
    → "The name field cannot be empty."
  • Cannot exceed max length (255 chars)
    → "Level name cannot exceed '255' characters."

🔹 5. shortName

  • Cannot be null or empty
    → "The shortName field cannot be empty."
  • Cannot exceed max length
    → "Level shortName cannot exceed '{MaxLength}' characters."

🔹 6. levelType

  • Must be provided and non-empty
    → "The levelType field cannot be empty."
  • Must be in the allowed types list (case-insensitive match)
    → "The levelType is invalid."

🔹 7. lvl (Level Index)

  • Must be present and a valid integer
    → "lvl must be a valid unique integer."
  • If a request-level _index is specified:
  • It must match lvl in the payload
    → "The requested level index and payload lvl information do not match."
  • If no _index is provided and a level with same lvl already exists:
    → "Building already has a level with the given level index."

  • If _index is provided but the level is not found:
    → "Level was not found with given lvl: {lvl}."

🔹 8. eid (External Identifier)

  • If present:
  • Must not be empty
    → "The eid field cannot be empty."
  • Must not be used by another level with different fid
    → "Another level exists with the same levelExternalIdentifier for this client."

🔹 9. Site and Building Existence

  • If sid does not resolve to a valid site:
    → "Site with siteIdentifier '{sid}' could not be found."

  • If bid does not resolve to a valid building:
    → "Building with buildingIdentifier '{bid}' could not be found."

This validation process ensures that level data submitted to the platform is accurate, complete, and adheres to both structural and contextual integrity constraints.