stac-node-validator
v2.0.0-rc.3
Published
STAC Validator for NodeJS
Downloads
2,577
Readme
stac-node-validator
Validate STAC Items, Catalogs, Collections and all STAC extensions in JavaScript/Typescript/Node environments.
Versions
Current version: 2.0.0-rc.3
| STAC Node Validator Version | Supported STAC Versions | | --------------------------- | -------------------------------- | | 1.1.0 / 1.2.x / 2.x.x | >= 1.0.0-rc.1 | | 0.4.x / 1.0.x | >= 1.0.0-beta.2 and < 1.0.0-rc.3 | | 0.3.0 | 1.0.0-beta.2 | | 0.2.1 | 1.0.0-beta.1 |
Quick Start
Two options:
- Go to check-stac.moregeo.it for an online validator.
npx stac-node-validator /path/to/your/file-or-folderto temporarily install the library and validate the provided file for folder. See the chapters below for advanced usage options.
Usage
CLI
Install a recent version of node (>= 22.1.0) and npm.
Then install the CLI on your computer:
npm install -g stac-node-validator- Validate a single file:
stac-node-validator /path/to/your/file.json - Validate multiple files:
stac-node-validator /path/to/your/catalog.json /path/to/your/item.json
Instead of paths to local files, you can also use HTTP(S) URLs. Other protocols such as S3 are not supported yet.
- Validate a single folder (considers all
jsonandgeojsonfiles in the given folder and all sub-folders):stac-node-validator ./stac-spec
Further options to add to the commands above:
- To validate against schemas in a local STAC folder (e.g.
devbranch):--schemas /path/to/stac/folder - To validate against a specific local schema (e.g. an external extension):
--schemaMap https://stac-extensions.github.io/foobar/v1.0.0/schema.json=./json-schema/schema.json - To not verify SSL/TLS certificates:
--ignoreCerts - Add
--verboseto get a more detailed output - Add
--strictto enable strict mode in validation for schemas and numbers (as defined by ajv for optionsstrictSchema,strictNumbersandstrictTuples) - To set the depth for folder traversal:
--depth 0(0 = no sub-folders, -1 = unlimited, default: -1) - To lint local JSON files:
--lint(add--verboseto get a diff with the changes required) - To format / pretty-print local JSON files:
--format(Attention: this will override the source files without warning!) - To run custom validation code:
--custom ./path/to/validation.js- The validation.js needs to contain a class that implements theBaseValidatorinterface. See custom.example.js for an example.
Note on API support: Validating lists of STAC items/collections (i.e. GET /collections and GET /collections/:id/items) is partially supported.
It only checks the contained items/collections, but not the other parts of the response (e.g. links).
You can also pass a config file via the --config option. Simply pass a file path as value.
Parameters set via CLI will not override the corresponding setting in the config file.
The config file uses the same option names as above.
To specify the files to be validated, add an array with paths.
The schema map is an object instead of string separated with a = character.
Programmatic
You can also use the validator programmatically in your JavaScript/NodeJS applications.
Install it into an existing project:
npm install stac-node-validatorFor browsers
Then in your code, you can for example do the following:
const validate = require('stac-node-validator');
// Add any options, e.g. strict mode
const config = {
strict: true,
};
// Validate a STAC file from a URL
const result = await validate('https://example.com/catalog.json', config);
// Check if validation passed
if (result.valid) {
console.log('STAC file is valid!');
} else {
console.log('STAC file has errors:');
}For NodeJS
const validate = require('stac-node-validator');
const nodeLoader = require('stac-node-validator/src/loader/node');
// Add any options
const config = {
loader: nodeLoader,
};
// Validate a STAC file from a URL
const result = await validate('https://example.com/catalog.json', config);
// Check if validation passed
if (result.valid) {
console.log('STAC file is valid!');
} else {
console.log('STAC file has errors:');
}JSON Schema Versions
By default, only JSON Schema draft-07 is supported (used by all core STAC schemas). Some extensions may use newer JSON Schema drafts (2019-09 or 2020-12).
The CLI automatically supports all three drafts.
For programmatic use, you can opt into newer drafts without affecting your bundle size
when you don't need them. Pass the Ajv classes via config.schemaVersions:
const validate = require('stac-node-validator');
const result = await validate(data, {
schemaVersions: {
'2019-09': require('ajv/dist/2019'),
'2020-12': require('ajv/dist/2020'),
},
});If a schema requires a draft that isn't provided, the validator will report an error indicating which draft is needed.
Validation Results
The validate function returns a Report object with the following structure:
{
id: "catalog.json", // File path or STAC ID
type: "Catalog", // STAC type (Catalog, Collection, Feature)
version: "1.0.0", // STAC version
valid: true, // Overall validation result
skipped: false, // Whether validation was skipped
messages: [], // Info/warning messages
children: [], // Child reports for collections/API responses
results: {
core: [], // Core schema validation errors
extensions: {}, // Extension validation errors (by schema URL)
custom: [] // Custom validation errors
},
apiList: false, // Whether this is an API collection response
source: null // Original file path (null for objects)
}Browser
The validator is available as browser bundles for client-side validation:
- ESM bundle (
dist/index.mjs) — recommended, self-contained. - UMD bundle (
dist/index.js) — deprecated, self-contained.
CDN Usage (ESM)
<script type="module">
import validate from 'https://cdn.jsdelivr.net/npm/stac-node-validator@2/dist/index.mjs';
const result = await validate({
stac_version: '1.0.0',
type: 'Catalog',
id: 'my-catalog',
description: 'A sample catalog',
links: [],
});
if (result.valid) {
console.log('STAC is valid!');
} else {
console.log('Validation errors:', result.results.core);
}
</script>CDN Usage (UMD)
<script src="https://cdn.jsdelivr.net/npm/stac-node-validator@2/dist/index.js"></script>
<script>
validate({
stac_version: '1.0.0',
type: 'Catalog',
id: 'my-catalog',
description: 'A sample catalog',
links: [],
}).then(function (result) {
if (result.valid) {
console.log('STAC is valid!');
} else {
console.log('Validation errors:', result.results.core);
}
});
</script>Custom Validators
You can extend the validator with custom validation logic by creating a class that extends BaseValidator. This lets you add domain-specific rules beyond what the STAC JSON Schemas cover.
Getting Started
Create a JavaScript file that extends BaseValidator and override one or more lifecycle methods:
const BaseValidator = require('stac-node-validator/src/baseValidator.js');
class CustomValidator extends BaseValidator {
async afterValidation(data, test, report, config) {
// data is the STAC object (a stac-js object if stac-js is installed)
// test provides assertion methods to collect errors
// report is the validation report
// config is the validator configuration
test.truthy(typeof data.title === 'string', 'must have a title');
test.equal(data.type, 'Collection', 'type must be Collection');
}
}
module.exports = CustomValidator;Run it via the CLI:
stac-node-validator /path/to/files --custom ./my-validator.jsOr programmatically:
const validate = require('stac-node-validator');
const CustomValidator = require('./my-validator.js');
const config = {
customValidator: new CustomValidator(),
};
const result = await validate('/path/to/file.json', config);Lifecycle Methods
A custom validator can override the following methods, which are called in order during validation:
createAjv(ajv)
Customize the ajv JSON Schema validator instance before schemas are compiled. Return the modified ajv instance.
async createAjv(ajv) {
ajv.addKeyword('x-custom-keyword');
return ajv;
}afterLoading(data, report, config)
Preprocess the STAC data after it has been loaded but before validation begins. Must return the (possibly modified) data object.
Warning: This may affect validation results!
For example, you can inject additional extension schemas to be validated:
async afterLoading(data, report, config) {
if (!Array.isArray(data.stac_extensions)) {
data.stac_extensions = [];
}
data.stac_extensions.push('https://example.com/my-schema/v1.0.0/schema.json');
return data;
}Or you could remove the collection property from Items:
async afterLoading(data, report, config) {
if (typeof data.collection !== 'undefined') {
delete data.collection;
}
return data;
}bypassValidation(data, report, config)
Return a Report object to skip the standard STAC validation entirely, or return null to continue with normal validation. This is useful for validating against a different schema (e.g., OGC API Records) instead of the STAC schemas.
async bypassValidation(data, report, config) {
if (typeof data.stac_version === 'undefined') {
// Not a STAC entity — validate against a different schema
// Then set report.valid to true/false for example
report.valid = true;
return report;
}
return null; // Continue with normal STAC validation
}afterValidation(data, test, report, config)
Run custom validation rules after the core and extension schema validation has completed. This is the most commonly used method. The data parameter is a stac-js object if the dependency is installed, otherwise the raw JSON object.
async afterValidation(data, test, report, config) {
// Require a specific license field on collections
if (data.type === 'Collection') {
test.truthy(
data.license === 'CC-BY-4.0',
'Collection must be CC-BY-4.0 licensed'
);
}
// Check that self links are provided
const selfLink = data.links?.find(l => l.rel === 'self');
test.truthy(selfLink, 'self link is required')
}Test Assertions
The test object passed to afterValidation wraps Node's built-in assert module. Instead of throwing on the first failure, it collects all errors so you get a complete report. Available methods:
| Method | Description |
| ---------------------------------------------------- | ----------------------------------------------------- |
| test.truthy(value, message) | Asserts that value is truthy |
| test.ok(value, message) | Same as truthy |
| test.equal(actual, expected, message) | Loose equality (==) |
| test.strictEqual(actual, expected, message) | Strict equality (===) |
| test.deepEqual(actual, expected, message) | Deep loose equality |
| test.deepStrictEqual(actual, expected, message) | Deep strict equality |
| test.notEqual(actual, expected, message) | Loose inequality |
| test.notStrictEqual(actual, expected, message) | Strict inequality |
| test.notDeepEqual(actual, expected, message) | Deep loose inequality |
| test.notDeepStrictEqual(actual, expected, message) | Deep strict inequality |
| test.match(string, regexp, message) | Asserts string matches regexp |
| test.doesNotMatch(string, regexp, message) | Asserts string does not match regexp |
| test.fail(message) | Unconditionally adds an error |
| test.ifError(value) | Fails if value is truthy (useful for error objects) |
| test.throws(fn, expected, message) | Asserts fn throws |
| test.doesNotThrow(fn, message) | Asserts fn does not throw |
| test.rejects(asyncFn, expected, message) | Asserts async function rejects |
| test.doesNotReject(asyncFn, message) | Asserts async function does not reject |
You can also simply throw an Error in any lifecycle method — it will be caught and added to report.results.custom as well.
Using Constructor State
You can use the constructor to initialize state that persists across validations of multiple files:
class CustomValidator extends BaseValidator {
constructor() {
super();
this.ids = new Set();
}
async afterValidation(data, test, report, config) {
// Check for duplicate IDs across files
test.truthy(!this.ids.has(data.id), `duplicate ID: ${data.id}`);
this.ids.add(data.id);
}
}Development
git clone https://github.com/moregeo-it/stac-node-validatorto clone the repocd stac-node-validatorto switch into the new folder created by gitnpm installto install dependencies- Run the commands as above, but replace
stac-node-validatorwithnode bin/cli.js, for examplenode bin/cli.js /path/to/your/file.json
Browser Bundle
To work on the browser bundle build it: npm run build
Then you can import it from the dist folder.
Tests
Simply run npm test in a working development environment.
To run the website tests (requires Playwright):
npx playwright install --with-deps chromium
npm run test:website