@varve/statcan-wds
v0.4.0
Published
An isomorphic, Zod-validated TypeScript client for the Statistics Canada Web Data Service (WDS) API.
Maintainers
Readme
@varve/statcan-wds
An isomorphic, Zod-validated TypeScript client for the Statistics Canada Web Data Service (WDS) API.
Features
- Pragmatic Validation: Every API response is validated at runtime using
zod. While we maintain strict typing, schemas are permissive regardingnullandoptionalfields to handle StatCan's inconsistent real-world data (e.g., suppressed metadata or Census edge cases). - Defensive Parsing: Specifically detects non-JSON responses (HTML error pages) and categorizes them into actionable error classes rather than crashing on generic syntax errors.
- Wrapper-friendly errors: Non-2xx responses expose top-level
status; rate-limit hints exposeretryAfterMswhen present. - Isomorphic: Works in Node.js, Next.js, Cloudflare Workers, and modern browsers.
- Complete Coverage: Supports all 16 data access and metadata endpoints documented in the official WDS specification.
Installation
npm install @varve/statcan-wds zod(Note: zod is a required peer dependency).
Quick Start
import { StatCanClient } from '@varve/statcan-wds';
async function main() {
const client = new StatCanClient();
// 1. Get Table Metadata
const metadata = await client.getCubeMetadata([35100003]);
console.log(metadata[0].object?.cubeTitleEn);
// 2. Fetch Data by Coordinate
const data = await client.getDataFromCubePidCoordAndLatestNPeriods([{
productId: 35100003,
coordinate: '1.12.0.0.0.0.0.0.0.0',
latestN: 3
}]);
console.log(data[0].object?.vectorDataPoint);
}
main();Error Handling
The client uses a hierarchy of specific error classes to help you handle StatCan's various failure modes:
| Error Class | Trigger |
| ----------- | ------- |
| InvalidCoordinateError | Thrown for 400 status codes or when the API returns "Response Code 1". |
| AgencyInternalError | Thrown when the agency returns a 500 HTML error page. |
| AgencyResponseError | Thrown for non-JSON content types or malformed JSON. |
| SuppressedDataError | Thrown when a series is requested but the API returns zero data points (suppressed data). |
| StatCanApiError | Generic catch-all for other non-200 API responses. |
import { StatCanClient, InvalidCoordinateError, SuppressedDataError } from '@varve/statcan-wds';
const client = new StatCanClient();
try {
const data = await client.getDataFromVectorsAndLatestNPeriods([{ vectorId: 999, latestN: 1 }]);
} catch (error) {
if (error instanceof InvalidCoordinateError) {
console.error("The requested vector ID or coordinate does not exist.");
} else if (error instanceof SuppressedDataError) {
console.error("The series exists but is currently suppressed (no data points).");
}
}Configuration
You can pass options to the client constructor to override the base URL (e.g., for local proxying) or request timeout. maxRetries is accepted for compatibility, but retry policy is owned by callers.
const client = new StatCanClient({
baseUrl: 'https://proxy.your-company.com/statcan',
maxRetries: 5, // accepted for compatibility; retries are handled by callers
timeoutMs: 30_000,
});Notes on Official Documentation
The official WDS user guide contains several discrepancies from the actual API behaviour, discovered through live testing against the production endpoints:
getChangedCubeListandgetChangedSeriesList: The docs show a double-nested response structure (object: [[...]]) that does not reflect what the API actually returns. The real response isobject: [...].valuefield in datapoints: One doc example shows"value": "18381"as a string. The API always returnsvalueas a JSON number ornull.geoAttributein cube metadata: The docs omit this, but the API can returnnullfor this field (not just absent). The schema accounts for this.getDataFromVectorByReferencePeriodRange: The docs showvectorIdsas a single quoted value. The API accepts a comma-separated list (e.g.vectorIds=1,2,3). This client's method acceptsnumber | number[]and handles the formatting.dimensionsingetAllCubesList: The field useshasUOM(capital) in the bulk list response, whereasgetCubeMetadatadimensions usehasUom. These are typed asunknown[]to handle the inconsistency safely.
The schemas in this package reflect observed live API behaviour, not the documentation.
License
MIT
