Adding a data source
ONgeoR contributors
Source:vignettes/adding-data-sources.Rmd
adding-data-sources.RmdAdding a source currently means changing the package. There is no
exported add_source_template() or
validate_source_registry() workflow. The existing retrieval
helper supports Ontario LIO ArcGIS REST layers that return GeoJSON; do
not describe another provider or file format as supported until
retrieval, validation, and tests for it exist.
Vet the source first
Before editing code, verify and record:
- the authoritative owner and publishing jurisdiction;
- the licence and whether redistribution or runtime retrieval is permitted;
- a stable ArcGIS REST MapServer layer URL and its
service_layerpath; - geometry type, schema, key identifier and name fields;
- observed feature count and whether it exceeds one response page;
- whether generalized geometry is valid for this particular layer.
Feature counts and schemas can change. Treat the registry values as reviewed metadata, not runtime guarantees.
Add the registry entry
Add an entry under sources: in
inst/extdata/sources.yaml. Existing entries use exactly
these fields:
sources:
example_source_id:
name: "Human-readable authoritative layer name"
service_layer: "LIO_OpenXX/0"
geography_type: "boundary"
feature_count: 123
update_frequency: "unknown"
key_fields: ["DOMAIN_ID", "ENGLISH_NAME"]
license: "Open Government Licence - Ontario"
source_url: "https://.../MapServer/0"Use a stable snake-case source id. Confirm that
key_fields exist in live output and that the licence text
and URL match the publisher. The package’s current YAML file contains a
Unicode dash in existing licence values, but new text can use an ASCII
hyphen without changing meaning.
Add a retrieval wrapper
Add a documented, exported wrapper in R/retrieve.R. It
should state the specific layer, parameters, return value, provenance,
and any limitations confirmed by live testing. The current LIO pattern
is:
#' Retrieve example boundaries
#'
#' @param simplify Logical. Whether to request generalized geometry.
#' @param refresh Logical. Whether to bypass the cache.
#' @return An `sf` object with provenance attributes.
#' @export
retrieve_example <- function(simplify = FALSE, refresh = FALSE) {
fetch_lio_sf(
service_layer = "LIO_OpenXX/0",
source_name = "Human-readable authoritative layer name",
simplify = simplify,
refresh = refresh
)
}Choose simplify from observed geometry quality, not
feature count alone. Check it by area, not by row count or geometry
type: the service answers a too-coarse maxAllowableOffset
with polygons that are still typed MULTIPOLYGON and still
29 rows, but whose small members have collapsed to zero area. Compare
each feature’s area against an unsimplified or finely simplified request
before trusting a layer’s simplified form.
Set paginate = TRUE only after confirming offset-based
pagination works for the layer. The cache key includes source name,
layer, filter, simplification, page size, pagination mode, and a
geometry-schema version, so changing any of those – or bumping the
schema when retrieved geometry changes shape for the same request –
produces a distinct cache entry. refresh = TRUE bypasses
and replaces the matching cached entry.
If a wrapper accepts a filter, validate or constrain it before
interpolating a LIO where expression. Keep source-specific
policy in the wrapper and common HTTP, conversion, provenance, and cache
behavior in fetch_lio_sf().
Paginated retrieval requests 2,000 features per page and stops after
20 pages, so the safety ceiling is 40,000 features. Retrieved row counts
are checked against the registry and warn when they differ by more than
20%. The optional update_frequency registry field records
source-maintenance metadata; it is currently informational only.
Wire the CLI dispatch
The registry does not automatically make a source retrievable by the
CLI. Update both switches in R/cli.R:
-
retrieve_by_source_id()maps the source id to the wrapper and passesrefresh. -
source_retrieve_call()emits the wrapper call used in generatedreproduce.Rscripts.
For example:
# In retrieve_by_source_id()
example_source_id = retrieve_example(refresh = refresh),
# In source_retrieve_call()
example_source_id = "retrieve_example()",These functions are internal, but both paths need tests because one executes retrieval and the other generates user-facing reproducibility code.
Test without depending on the service
Use mocked HTTP responses or synthetic sf data for
routine tests. Cover:
- wrapper arguments passed to
fetch_lio_sf(); - returned geometry and
source_url,source_name,retrieved_atattributes; - cache reuse and
refresh = TRUEbehavior; - pagination termination, page combination, and the existing hard page cap when pagination is enabled;
- simplified and unsimplified query construction where supported;
- both CLI dispatch functions and unknown-id errors;
- identifier and name detection when the source will be used by
resolve()orbuild_crosswalk().
Live validation is still needed before accepting the source, but it should be an explicit manual check rather than a network dependency in the test suite or vignettes. Record observed feature count, schema, geometry type, paging, and simplification results in the change description.
Document and check
Run roxygen to update NAMESPACE and the generated
.Rd file, then run the focused tests, the full test suite,
and devtools::check() with vignettes. Review the generated
reproducer call, confirm no live API request occurred during package
checking, run git diff --check, and inspect the diff for
credentials or downloaded data before proposing a commit.