Last Updated: January 28, 2026
Repository: OS4CSAPI/ogc-client-CSAPI
Validated Commit: a71706b9592cad7a5ad06e6cf8ddc41fa5387732
This document provides a comprehensive, accurate reference for validation capabilities in the OGC-Client-CSAPI library. It clearly distinguishes between what validations ARE implemented and what validations are NOT implemented (despite claims that may exist in other documentation).
Purpose: Prevent confusion, runtime errors, and incorrect assumptions about validation scope by documenting actual capabilities.
Critical Note: All validators use structural validation (manual type checking, property validation) rather than schema-based validation (fetching and validating against OGC JSON schemas). This is an important architectural distinction.
All three validation systems (GeoJSON, SWE Common, SensorML) implement manual structural validation:
- Type Checking: Runtime TypeScript type guards and discriminators
- Required Properties: Explicit checks for mandatory fields (uid, featureType, definition, etc.)
- Type-Specific Rules: Custom validation logic for each resource/component type
- Constraint Validation: Interval checking, pattern matching, format validation
- Manual Property Inspection: Direct object property access and validation
Advantages:
- Fast execution (no network requests)
- No external dependencies
- Predictable behavior
- Works offline
Limitations:
- Not guaranteed to match OGC JSON schemas exactly
- Must be manually updated when specifications change
- May miss subtle schema violations
Despite documentation claims, the validators do NOT:
- ❌ Fetch OGC JSON schemas from
schemas.opengis.net - ❌ Validate using Ajv (Another JSON Schema Validator) against fetched schemas
- ❌ Cache downloaded schemas for performance
- ❌ Provide JSON Schema compliance guarantees
Why This Matters: Users expecting strict OGC JSON Schema compliance should be aware that validation is structural and may not catch all schema violations.
Location: src/ogc-api/csapi/validation/geojson-validator.ts
Test Count: 61 tests
Code Coverage: 40.95%
Feature Validators (7 types):
validateSystemFeature(feature)- System/Sensor feature validationvalidateDeploymentFeature(feature)- Deployment feature validationvalidateProcedureFeature(feature)- Procedure feature validationvalidateSamplingFeature(feature)- Sampling Feature validationvalidatePropertyFeature(feature)- Observable/Controllable Property validationvalidateDatastreamFeature(feature)- Datastream feature validationvalidateControlStreamFeature(feature)- Control Stream feature validation
Collection Validators (7 types):
validateSystemFeatureCollection(collection)- Validates FeatureCollection of SystemsvalidateDeploymentFeatureCollection(collection)- Validates FeatureCollection of DeploymentsvalidateProcedureFeatureCollection(collection)- Validates FeatureCollection of ProceduresvalidateSamplingFeatureCollection(collection)- Validates FeatureCollection of Sampling FeaturesvalidatePropertyFeatureCollection(collection)- Validates FeatureCollection of PropertiesvalidateDatastreamFeatureCollection(collection)- Validates FeatureCollection of DatastreamsvalidateControlStreamFeatureCollection(collection)- Validates FeatureCollection of Control Streams
Type Guards (7 types):
isSystemFeature(feature)- Type guard for System featuresisDeploymentFeature(feature)- Type guard for Deployment featuresisProcedureFeature(feature)- Type guard for Procedure featuresisSamplingFeature(feature)- Type guard for Sampling FeaturesisPropertyFeature(feature)- Type guard for Property featuresisDatastreamFeature(feature)- Type guard for Datastream featuresisControlStreamFeature(feature)- Type guard for Control Stream features
What Each Validator Checks:
✅ GeoJSON Structure:
type: 'Feature'ortype: 'FeatureCollection'presentpropertiesobject existsgeometryfield present (nullable)
✅ CSAPI Required Properties:
uid(unique identifier) present and non-emptyfeatureTypematches expected type (e.g., "http://www.w3.org/ns/sosa/System")namepresent (optional in some types)
✅ Type-Specific Requirements:
- Deployments:
systemreference link present - Datastreams:
systemandobservedPropertyreference links present - Control Streams:
systemandcontrolledPropertyreference links present - Properties:
definitionfield present
✅ Error Reporting:
- Detailed error messages with property paths
- Error aggregation for collections (with index tracking)
- Validation result structure:
{ valid: boolean, errors: ValidationError[] }
Geometry Validation:
- ❌ Coordinate validation (no bbox checks, dimension validation)
- ❌ Geometry type checking (no validation that geometry matches expected type)
- ❌ GeometryCollection validation (basic types only: Point, LineString, Polygon, Multi*)
- ❌ Spatial relationship validation
- ❌ CRS (Coordinate Reference System) validation
Link Validation:
- ❌ No
validateLinks()function exists - ❌ No validation of
linksarray structure - ❌ No
rel(relation) checking - ❌ No
href(URL) format validation - ❌ No validation that required links are present
Temporal Validation:
- ❌ No
validateTemporal()function exists - ❌ No ISO 8601 date/time format validation
- ❌ No temporal extent validation
- ❌ No deployment period validation (despite being mentioned in validator description)
- ❌ No validation of
phenomenonTimeorresultTimeformats
Type-Specific Advanced Validation:
- ❌ Deployment period structure validation
- ❌ Procedure definition/metadata validation (only checks existence)
- ❌ Sampling Feature
featureOfInterestproperties validation - ❌ Sampling Feature spatial extent validation
- ❌ Datastream/Control Stream schema validation (only checks reference existence)
Collection Validators (0% Test Coverage): All seven collection validators have zero test execution coverage. They consist primarily of iteration logic that applies single-feature validators to arrays. While the underlying validation logic IS tested, the collection-specific error aggregation and iteration code is not.
Recommendation: Test collection validators or use single-feature validators in loops for mission-critical validation.
Valid Usage:
import { validateSystemFeature, isSystemFeature } from 'ogc-client/csapi/validation';
// Basic feature validation
const result = validateSystemFeature(feature);
if (!result.valid) {
console.error('Validation errors:', result.errors);
}
// Type guard usage
if (isSystemFeature(feature)) {
// TypeScript knows this is a SystemFeature
console.log(feature.properties.name);
}What WON'T Work:
// ❌ These functions do NOT exist
validateGeometry(feature.geometry); // Error: function not found
validateLinks(feature.links); // Error: function not found
validateTemporal(feature.properties.phenomenonTime); // Error: function not foundWorkarounds for Missing Validation:
// Manual geometry validation
function validateGeometryManually(geometry: GeoJSONGeometry): boolean {
if (!geometry || !geometry.type) return false;
switch (geometry.type) {
case 'Point':
return Array.isArray(geometry.coordinates) && geometry.coordinates.length >= 2;
case 'LineString':
return Array.isArray(geometry.coordinates) && geometry.coordinates.length >= 2;
// ... add other types as needed
default:
return false;
}
}
// Manual link validation
function validateLinksManually(links: any[]): boolean {
if (!Array.isArray(links)) return false;
return links.every(link =>
typeof link.rel === 'string' &&
typeof link.href === 'string' &&
(link.href.startsWith('http://') || link.href.startsWith('https://'))
);
}
// Manual temporal validation
function validateISO8601(dateString: string): boolean {
const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?$/;
return iso8601Regex.test(dateString);
}Location: src/ogc-api/csapi/validation/swe-validator.ts (component validation)
Location: src/ogc-api/csapi/validation/constraint-validator.ts (constraint validation)
Test Count: 78 tests (50 component + 28 constraint)
Code Coverage: 73.68%
Simple Component Validators (6 types):
validateBoolean(component)- Boolean component validationvalidateCount(component)- Count (integer) component validationvalidateQuantity(component)- Quantity (decimal) component validationvalidateText(component)- Text component validationvalidateCategory(component)- Category (coded value) component validationvalidateTime(component)- Time component validation
Range Component Validator (1 generic for 4 types):
validateRangeComponent(component)- Generic validator for QuantityRange, CountRange, TimeRange, CategoryRange
Aggregate Component Validators (3 types):
validateDataRecord(component)- DataRecord (field collection) validationvalidateDataArray(component)- DataArray (element array) validationvalidateObservationResult(result)- Observation result structure validation (⚠️ UNTESTED - 0% coverage)
Constraint Validators (3 types):
validateAllowedValues(constraint, value)- Numeric interval validation with significant figuresvalidateAllowedTokens(constraint, value)- Text pattern/regex validationvalidateAllowedTimes(constraint, value)- Temporal interval validation
Exported from swe/index.ts:
export {
validateDataRecord,
validateBoolean,
validateCount,
validateQuantity,
validateText,
validateCategory,
validateTime,
validateDataArray,
validateObservationResult,
validateRangeComponent,
validateAllowedValues,
validateAllowedTokens,
validateAllowedTimes,
validateSWEComponent // Generic dispatcher
} from './swe-validator';What Each Validator Checks:
✅ Type Validation:
- Correct
typefield (e.g., "Quantity", "DataRecord") - Required type-specific properties
✅ UoM (Unit of Measure) Validation:
- Present where required (Quantity, QuantityRange)
- Valid structure (code, href, or symbol)
✅ Constraint Validation:
AllowedValues: Interval checking (min/max), significant figures enforcementAllowedTokens: Pattern matching with regex supportAllowedTimes: Temporal constraint validation
✅ Aggregate Structure Validation:
- DataRecord:
fieldsarray exists - DataArray:
elementTypeandelementCountpresent - ObservationResult: Basic structure validation (
⚠️ untested)
✅ Reference Frame Validation:
- Vector reference frame validation
- Coordinate system checking
Missing Component Validators (8 types):
These validators were claimed in some documentation but are NOT exported from swe/index.ts and/or NOT implemented in swe-validator.ts:
- ❌
validateQuantityRange()- UsevalidateRangeComponent()instead - ❌
validateCategoryRange()- UsevalidateRangeComponent()instead - ❌
validateCountRange()- UsevalidateRangeComponent()instead - ❌
validateTimeRange()- UsevalidateRangeComponent()instead - ❌
validateAbstractDataComponent()- NOT implemented - ❌
validateAbstractSimpleComponent()- NOT implemented - ❌
validateGeometryData()- NOT implemented - ❌
validateNilValues()- NOT implemented
Missing Component Type Support:
The generic validateSWEComponent() dispatcher returns { valid: true } without validation for:
- ❌
Vector(claimed but not validated) - ❌
Matrix(claimed but not validated) - ❌
DataStream(claimed but not validated) - ❌
DataChoice(claimed but not validated) - ❌
Geometry(claimed but not validated) - ❌ Boolean type validators for geometry types (Point, LineString, Polygon, etc.)
Missing Specification Compliance:
- ❌ Required OGC properties NOT validated:
definition(mandatory per OGC 24-014) - NOT checkedlabel(mandatory per OGC 24-014) - NOT checked
- ❌ Deep nested validation requires manual recursive calls (not automatic)
validateObservationResult() is UNTESTED: This function has 0% test execution coverage (0 calls in test suite). Use with caution or implement additional testing.
Constraint Validation is Excellent: The constraint validation system (intervals, patterns, significant figures) is comprehensively tested and can be relied upon. This is the strength of the validation system.
Aggregate Validation is Basic:
validateDataRecord() and validateDataArray() check only basic structure (field array exists, element type present) without recursively validating nested component structures.
Valid Usage:
import {
validateQuantity,
validateDataRecord,
validateAllowedValues,
validateRangeComponent // Use this for all Range types
} from 'ogc-client/csapi/validation';
// Simple component validation
const quantityResult = validateQuantity(component);
if (!quantityResult.valid) {
console.error('Invalid Quantity:', quantityResult.errors);
}
// Constraint validation
const constraintResult = validateAllowedValues(constraint, value);
if (!constraintResult.valid) {
console.error('Value violates constraint:', constraintResult.errors);
}
// Range validation (generic for all range types)
const rangeResult = validateRangeComponent(quantityRangeComponent);What WON'T Work:
// ❌ These functions do NOT exist or are NOT exported
validateQuantityRange(component); // Error: not exported (use validateRangeComponent)
validateVector(component); // Error: returns { valid: true } without validation
validateMatrix(component); // Error: returns { valid: true } without validation
validateGeometryData(component); // Error: function not found
validateNilValues(component); // Error: function not foundWorkaround for Missing Validators:
// For Range types, use the generic validator
import { validateRangeComponent } from 'ogc-client/csapi/validation';
// Works for QuantityRange, CountRange, TimeRange, CategoryRange
const result = validateRangeComponent(rangeComponent);
// For unsupported types, implement custom validation
function validateVectorManually(component: any): boolean {
if (component.type !== 'Vector') return false;
if (!component.referenceFrame) return false;
if (!Array.isArray(component.coordinates)) return false;
// Add more checks as needed
return true;
}Location: src/ogc-api/csapi/validation/sensorml-validator.ts
Test Count: 13 tests
Code Coverage: Not measured (no coverage report available)
Process Validators:
validateSensorMLProcess(process)- Validates PhysicalSystem, PhysicalComponent, SimpleProcess, AggregateProcessvalidateDeployment(deployment)- Validates Deployment metadatavalidateDerivedProperty(property)- Validates derived property definitions
What Each Validator Checks:
✅ Structural Validation:
- Required properties present (
type,id,name, etc.) - Type-specific constraints (e.g., PhysicalSystem has
components) - Array structure validation (components, inputs, outputs)
✅ Type Checking:
- Process type validation (PhysicalSystem, PhysicalComponent, SimpleProcess, AggregateProcess)
- Nested object structure validation
✅ Format Validation:
- Custom format validators added to Ajv:
uri- Validates URIs (both URLs and URNs)iso-datetime- Basic ISO 8601 date/time validationgeojson-geometry- Basic GeoJSON geometry structure check
✅ Required Properties:
typefield presenceidfield presence- Type-specific required properties
Schema-Based Validation:
- ❌ Does NOT fetch OGC JSON schemas from
schemas.opengis.net - ❌ Does NOT validate against actual OGC JSON schemas
- ❌ Does NOT use Ajv for schema validation (Ajv is imported and configured but never used)
- ❌ Does NOT cache schemas (no schemas to cache)
What the Code Actually Does:
The sensorml-validator.ts file contains this revealing comment:
async function initializeValidator(): Promise<Ajv> {
// ...
ajvInstance = new Ajv({
strict: false,
allErrors: true,
verbose: true,
});
addFormats(ajvInstance);
// In a real implementation, schemas would be fetched and cached
// For now, we'll do basic structural validation ← ACTUAL APPROACH
schemasLoaded = true;
return ajvInstance;
}Schema URLs Defined But Never Used:
export const SENSORML_SCHEMA_URLS = {
PhysicalSystem: 'https://schemas.opengis.net/sensorML/3.0/json/physicalSystem.json',
PhysicalComponent: 'https://schemas.opengis.net/sensorML/3.0/json/physicalComponent.json',
// ... URLs exist but are NEVER fetched
};Why Functions Are Async:
Functions are declared async but don't actually perform any asynchronous operations (no await, no network requests). This suggests the async nature was planned for schema fetching but never implemented.
What Documentation Claims:
"Async validation against OGC JSON schemas from schemas.opengis.net"
"JSON Schema compliance checking using Ajv"
"Schema caching for performance"
What Actually Happens:
- ✅ Structural validation with manual type checking
- ✅ Required property enforcement
- ✅ Format validation for URIs and dates
- ❌ NO schema fetching
- ❌ NO Ajv validation against schemas
- ❌ NO schema caching (nothing to cache)
Practical Impact: The validators work and provide useful structural validation, but they do NOT guarantee strict OGC JSON Schema compliance. Subtle schema violations may not be caught.
Valid Usage:
import {
validateSensorMLProcess,
validateDeployment,
validateDerivedProperty
} from 'ogc-client/csapi/validation';
// Process validation (works for all process types)
const result = await validateSensorMLProcess(physicalSystem);
if (!result.valid) {
console.error('Invalid process:', result.errors);
}
// Deployment validation
const deploymentResult = await validateDeployment(deployment);
// Property validation
const propertyResult = await validateDerivedProperty(property);What to Expect:
// ✅ Will catch:
- Missing required properties (type, id, name)
- Wrong process type
- Invalid URI formats
- Malformed nested structures
// ❌ May NOT catch:
- Subtle JSON Schema violations
- Properties not matching exact OGC schemas
- Complex schema constraints not manually implemented
- Additional properties not in schemaImportant Note:
Functions are async but don't need to be await-ed in most cases since they perform no actual async operations:
// This works, but the await is unnecessary
const result = await validateSensorMLProcess(process);
// This also works (though TypeScript may warn)
const result = validateSensorMLProcess(process);| Validation System | Implemented | Claimed But Missing | Approach |
|---|---|---|---|
| GeoJSON | 21 validators (7 feature + 7 collection + 7 type guards) | Geometry validation, Link validation, Temporal validation, GeometryCollection support | Structural |
| SWE Common | 9 component validators + 3 constraint validators | 8 component validators (ranges as separate functions, abstract validators, geometry/nil validators), Required OGC property validation | Structural |
| SensorML | 3 process validators | OGC schema fetching, Ajv schema validation, Schema caching | Structural (NOT schema-based) |
Overall Assessment:
- ✅ Core structural validation works and is production-ready for basic use cases
⚠️ Advanced validation features are limited or missing- ❌ Schema-based validation is NOT implemented despite documentation suggesting it is
- ✅ Constraint validation (SWE Common) is excellent and comprehensive
What You Thought:
"The library validates against OGC JSON schemas fetched from schemas.opengis.net"
Reality: The library uses structural validation, not schema-based validation.
What This Means:
- No network requests for schemas
- Faster validation (no async operations needed)
- Works offline
- May not catch all OGC specification violations
Recommendation: If strict schema compliance is required, consider:
- Using a separate JSON Schema validator library (like Ajv) with OGC schemas
- Implementing additional validation checks
- Testing against reference implementations
What You Thought:
"The library validates geometries, links, and temporal data"
Reality: Only basic GeoJSON structure and CSAPI-specific properties are validated.
What This Means:
- Geometry coordinates are NOT validated
- Links array is NOT validated
- ISO 8601 temporal formats are NOT validated
- GeometryCollection is NOT supported
Recommendation: Implement custom validation for:
- Geometry coordinate validation (use a GeoJSON validation library)
- Link structure validation (check rel, href, type fields)
- Temporal format validation (use date parsing libraries)
What You Thought:
"The library validates all 24 SWE Common component types"
Reality:
Only 9 component validators are implemented, and 5 types return { valid: true } without validation.
What This Means:
- Vector, Matrix, DataStream, DataChoice, Geometry: NO validation
- Range validators: Use generic
validateRangeComponent()instead of type-specific functions - Definition and label: NOT validated (despite being OGC-required)
Recommendation: For unsupported types:
- Implement custom validation logic
- Use type guards to check structure
- Consider testing against reference implementations
DO:
- ✅ Use validators for basic structural validation
- ✅ Rely on constraint validation (intervals, patterns, significant figures)
- ✅ Use type guards for type checking
- ✅ Implement additional validation for advanced features
- ✅ Test thoroughly with real data
DON'T:
- ❌ Assume schema-based validation is happening
- ❌ Rely solely on validators for production data quality
- ❌ Use functions that don't exist (check this doc first)
- ❌ Expect validation of geometries, links, or temporal data
- ❌ Assume all SWE Common types are validated
High Priority:
- Correct all documentation claiming schema-based validation
- Document which validators exist vs which are claimed
- Add tests for collection validators (currently 0% coverage)
- Test
validateObservationResult()(currently 0% coverage)
Medium Priority:
- Implement geometry validation (coordinates, types, GeometryCollection)
- Implement link validation (structure, URL format)
- Implement temporal validation (ISO 8601 format)
- Implement missing SWE Common validators (Vector, Matrix, DataStream, DataChoice, Geometry)
- Add definition/label validation per OGC 24-014
Low Priority:
- Consider implementing actual schema-based validation (fetch from schemas.opengis.net)
- Use Ajv for JSON Schema validation
- Implement schema caching
- Add deep recursive validation for aggregate SWE Common types
- Issue #12 - GeoJSON validation discrepancies
- Issue #14 - SWE Common missing validators
- Issue #15 - SensorML structural validation approach
- Issue #25 - Correct GeoJSON coverage claim
- Issue #26 - Correct SWE Common coverage claim
- Issue #27 - Update validation capabilities documentation (this document)
| Date | Version | Changes |
|---|---|---|
| 2026-01-28 | 1.0 | Initial comprehensive validation capabilities reference |
Questions or Issues?
If you discover additional discrepancies between claimed and actual validation capabilities, please open an issue in the CSAPI-Live-Testing repository.