Parameter Management¶
This document explains the comprehensive parameter management system in openEO by TiTiler, which provides dynamic parameter substitution for both synchronous result processing and XYZ tile services.
Overview¶
The parameter management system allows you to create flexible, reusable process graphs that can accept dynamic parameters at runtime. This enables:
- Dynamic Query Parameters: Pass parameters via query strings in API requests
- Default Parameter Values: Define fallback values in process graph definitions
- Automatic Parameter Injection: Built-in injection of system parameters like user information
- Parameter Precedence: Clear hierarchy for parameter resolution
Parameter Types¶
1. Process Graph Parameters¶
Parameters defined in the process graph definition with optional default values:
{
"process_graph": {
"load1": {
"process_id": "load_collection",
"arguments": {
"id": "S2",
"spatial_extent": { "from_parameter": "bbox" },
"temporal_extent": { "from_parameter": "time_range" }
},
"result": true
}
},
"parameters": [
{
"name": "bbox",
"description": "Spatial bounding box",
"schema": { "type": "object" },
"default": {
"west": 16.1,
"east": 16.6,
"north": 48.6,
"south": 47.2
}
},
{
"name": "time_range",
"description": "Temporal extent",
"schema": { "type": "array" },
"default": ["2023-01-01", "2023-12-31"]
}
]
}
2. Query Parameters¶
Parameters passed in the URL query string that override defaults:
# Override bbox parameter
GET /result?bbox={"west":10.0,"east":20.0,"north":50.0,"south":40.0}
# Override multiple parameters
GET /services/xyz/{service_id}/tiles/{z}/{x}/{y}?time_range=["2024-01-01","2024-06-30"]&bands=["red","green","blue"]
3. Reserved System Parameters¶
Automatically injected parameters that provide system context:
| Parameter | Description | Available In | Comment |
|---|---|---|---|
_openeo_user |
Authenticated user object | Both endpoints | |
_openeo_tile_store |
Tile storage backend | XYZ services only | |
spatial_extent_* |
Tile boundary coordinates | XYZ services only | Deprecated. Will be removed in a future release. Use bounding_box instead. |
tile_x, tile_y, tile_z |
Tile coordinates | XYZ services only | |
bounding_box |
Tile bounding box object | XYZ services only |
Parameter Resolution Priority¶
Parameters are resolved in the following order (highest to lowest priority):
- Query Parameters: Values passed in the URL query string
- System Parameters: Automatically injected reserved parameters
- Default Values: Default values defined in the process graph parameters
- Process Defaults: Built-in default values from process implementations
Endpoint Support¶
POST /result (Synchronous Processing)¶
The /result endpoint supports full parameter management:
POST /result?temporal_extent=["2024-01-01","2024-12-31"]&bands=["B04","B08"]
Content-Type: application/json
{
"process": {
"process_graph": {
"load1": {
"process_id": "load_collection",
"arguments": {
"id": "S2",
"temporal_extent": {"from_parameter": "temporal_extent"},
"bands": {"from_parameter": "bands"}
},
"result": true
}
},
"parameters": [
{
"name": "temporal_extent",
"schema": {"type": "array"},
"default": ["2023-01-01", "2023-12-31"]
},
{
"name": "bands",
"schema": {"type": "array"},
"default": ["B04", "B03", "B02"]
}
]
}
}
Features:
- Query parameter parsing and JSON deserialization
- User injection via
_openeo_userparameter - Default parameter value application
- Built-in parameter substitution via OpenEO process graph parser
GET /services/xyz/{service_id}/tiles/{z}/{x}/{y} (XYZ Tile Service)¶
XYZ tile services support the same parameter management with additional spatial context:
Additional Features:
- Automatic spatial parameter injection (tile bounds, coordinates)
- Tile-specific context parameters
- Same query parameter and default value support as
/result
Parameter Validation¶
JSON Parameter Validation¶
Complex parameters passed as query strings are automatically parsed as JSON:
# Array parameter
?bands=["red","green","blue"]
# Object parameter
?bounding_box={"west":10,"east":20,"north":50,"south":40}
# Nested object parameter
?filter_options={"cloud_cover":{"max":20},"processing_level":"L2A"}
Schema Validation¶
Parameters are validated against their schema definitions:
{
"name": "cloud_cover_max",
"description": "Maximum cloud cover percentage",
"schema": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"default": 20
}
Best Practices¶
1. Parameter Naming¶
- Use descriptive, lowercase parameter names
- Use underscores for multi-word parameters:
temporal_extent,cloud_cover_max - Avoid conflicts with reserved parameter names (
_openeo_*)
2. Default Values¶
- Always provide sensible default values for optional parameters
- Ensure defaults work across your expected data collections and time ranges
- Document the reasoning behind default choices
3. Parameter Documentation¶
{
"name": "temporal_extent",
"description": "Temporal extent as [start_date, end_date] in ISO 8601 format",
"schema": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"items": { "type": "string", "format": "date" }
},
"default": ["2023-01-01", "2023-12-31"],
"examples": [
["2024-01-01", "2024-06-30"],
["2023-07-15", "2023-08-15"]
]
}
4. Complex Parameters¶
For complex nested parameters, use clear structure and validation:
{
"name": "processing_options",
"description": "Processing configuration options",
"schema": {
"type": "object",
"properties": {
"cloud_mask": { "type": "boolean", "default": true },
"atmospheric_correction": { "type": "boolean", "default": false },
"resampling": {
"type": "string",
"enum": ["nearest", "bilinear", "cubic"],
"default": "bilinear"
}
}
},
"default": {
"cloud_mask": true,
"atmospheric_correction": false,
"resampling": "bilinear"
}
}
Examples¶
Basic Parameter Usage¶
Simple parameter substitution with defaults:
{
"process_graph": {
"load1": {
"process_id": "load_collection",
"arguments": {
"id": { "from_parameter": "collection" },
"temporal_extent": { "from_parameter": "time_range" }
},
"result": true
}
},
"parameters": [
{
"name": "collection",
"schema": { "type": "string" },
"default": "S2"
},
{
"name": "time_range",
"schema": { "type": "array" },
"default": ["2023-01-01", "2023-12-31"]
}
]
}
Usage: POST /result?collection=L8&time_range=["2024-01-01","2024-06-30"]
Advanced Parameter Usage¶
Complex parameters with validation and user context:
{
"process_graph": {
"load1": {
"process_id": "load_collection",
"arguments": {
"id": "S2",
"spatial_extent": { "from_parameter": "bbox" },
"temporal_extent": { "from_parameter": "time_range" }
}
},
"filter1": {
"process_id": "filter_bands",
"arguments": {
"data": { "from_node": "load1" },
"bands": { "from_parameter": "bands" }
}
},
"user_process": {
"process_id": "custom_user_process",
"arguments": {
"data": { "from_node": "filter1" },
"user_id": { "from_parameter": "_openeo_user" }
},
"result": true
}
},
"parameters": [
{
"name": "bbox",
"description": "Spatial bounding box",
"schema": {
"type": "object",
"required": ["west", "east", "north", "south"],
"properties": {
"west": { "type": "number" },
"east": { "type": "number" },
"north": { "type": "number" },
"south": { "type": "number" }
}
}
},
{
"name": "time_range",
"schema": { "type": "array" },
"default": ["2023-01-01", "2023-12-31"]
},
{
"name": "bands",
"schema": { "type": "array" },
"default": ["B04", "B03", "B02"]
}
]
}
Parameter Scope in Callbacks¶
Callback processes (reducer in reduce_dimension, process in apply / apply_dimension, etc.) have their own parameter scope. Per the openEO spec, a callback receives only the parameters it declares (data, context, etc.) — top-level UDP parameters are not automatically visible inside a callback.
The correct way to pass UDP-level parameters into a callback is through the context argument, which is designed exactly for this purpose.
Option A — single value (when the callback only needs one parameter):
{
"process_id": "apply_dimension",
"arguments": {
"data": { "from_node": "load1" },
"dimension": "bands",
"context": { "from_parameter": "indicator" },
"process": {
"process_graph": {
"eq1": {
"process_id": "eq",
"arguments": {
"x": { "from_parameter": "data" },
"y": { "from_parameter": "context" }
},
"result": true
}
}
}
}
}
Here context is the resolved value of indicator directly, so {"from_parameter": "context"} inside the callback equals e.g. 3.
Option B — dict (when the callback needs multiple parameters by name):
{
"process_id": "apply_dimension",
"arguments": {
"data": { "from_node": "load1" },
"dimension": "bands",
"context": {
"indicator": { "from_parameter": "indicator" },
"min_value": { "from_parameter": "min_value" },
"max_value": { "from_parameter": "max_value" }
},
"process": {
"process_graph": {
"get_indicator": {
"process_id": "array_element",
"arguments": {
"data": { "from_parameter": "context" },
"label": "indicator"
}
},
"eq1": {
"process_id": "eq",
"arguments": {
"x": { "from_parameter": "data" },
"y": { "from_node": "get_indicator" }
},
"result": true
}
}
}
}
}
context becomes a dict; use array_element with label to extract individual values by name inside the callback.
Option C — array by position (less readable, avoid unless needed):
"context": [
{ "from_parameter": "indicator" },
{ "from_parameter": "min_value" },
{ "from_parameter": "max_value" }
]
Inside the callback, extract by index: array_element({"from_parameter": "context"}, 0) gives indicator.
The from_parameter references inside context are resolved against the UDP's named_parameters before the callback is invoked, so the callback receives actual values (integers, strings, etc.) — not unresolved references.
Note: If you used a Python closure to capture
Parameterobjects from the openeo-python-client and referenced them directly inside a callback without passing throughcontext, those references would not resolve correctly. Always usecontextto thread outer parameters into callbacks.
Referencing a Stored UDP¶
A process graph can extend another graph by referencing a stored user-defined process by its process_id, exactly as it would reference a predefined process. Given a UDP saved as true_color through PUT /process_graphs/true_color:
{
"process_graph": {
"rendered": {
"process_id": "true_color",
"arguments": {
"bbox": { "west": -74.02, "east": -73.94, "south": 40.70, "north": 40.80 }
},
"result": true
}
}
}
The reference is inlined — with its arguments bound to the UDP's parameters — before the graph is parsed, so the executed graph is the UDP's own nodes. This happens on POST /validation, POST /result and POST /services.
A few properties worth knowing:
- UDPs are per-user. A reference resolves only against process graphs stored by the authenticated user; there is no shared or public UDP namespace.
- References work inside callbacks too. A UDP referenced from a
reducer,processor any other callback graph is inlined just like a top-level one, at any nesting depth. - Services are resolved once, at creation.
POST /servicesinlines the reference into the stored service definition, because XYZ tiles are rendered later without an authenticated user and cannot look the UDP up themselves. Updating a UDP therefore does not change services created from it — recreate the service to pick up the new definition. This is the one place resolution doesn't stay live: everywhere else (/validation,/result, and a stored UDP that itself references another UDP) there's always an authenticated user available, so the reference is resolved fresh, from whatever it currently looks like, every time. - Bind either all of the UDP's parameters, or none of them. Arguments passed to the reference are bound into the inlined graph. If you pass no arguments at all, the UDP's
from_parameterreferences are left in place and resolved later by the usual parameter machinery — query parameters and defaults still apply. Passing some arguments but not others is not currently supported: the unbound parameter has nothing to bind to, and the reference fails to resolve withProcess '<id>' not found in registry. - Unknown processes still error. A
process_idthat matches neither a predefined process nor one of your stored UDPs fails withProcessUnsupported, as before.
Troubleshooting¶
Common Issues¶
-
Parameter Not Found: Ensure parameter names match exactly between
from_parameterreferences and parameter definitions. -
Invalid JSON in Query: When passing complex parameters, ensure proper URL encoding:
# Correct
?bbox=%7B%22west%22%3A10%2C%22east%22%3A20%7D
# Also correct (many tools handle this automatically)
?bbox={"west":10,"east":20}
- Type Validation Errors: Ensure parameter values match their schema types:
- Reserved Parameter Conflicts: Don't define parameters that conflict with reserved names (
_openeo_*,spatial_extent_*,tile_*).
Debugging¶
Enable debug logging to see parameter resolution:
This will show:
- Query parameter parsing results
- Default parameter application
- Final parameter values passed to process graph