ecolod.org › GraphQL
A read-only GraphQL facade over the ecolod economic-statistics graph (3,544,395 triples of country-level indicators). Queries are translated to SPARQL and run against the vetted /sparql path — no SPARQL knowledge required. No auth, CORS open to every origin, introspection enabled.
The data is published under CC BY 4.0. Attribute Team KitaSan / ecolod.org. Questions, corrections and bulk-access requests: info@ecolod.org.
POST https://q.ecolod.org/graphql Content-Type: application/json {"query": "...", "variables": {...}}
POST https://q.ecolod.org/graphql Content-Type: application/graphql (raw query in the body)
GET https://q.ecolod.org/graphql?query={GraphQL}
Visiting with no query shows this page.
Each → line is a transcript of the command above it, run against the
store this endpoint serves. Country codes are ISO-3166-1 alpha-3; indicator ids are the
slug (gdp-nominal-usd) or the source's own code (NGDPD).
curl -s https://q.ecolod.org/graphql -H 'Content-Type: application/json' \
-d '{"query":"{ series(country:\"JPN\", indicator:\"gdp-nominal-usd\", from:2020, to:2024){ observations { year value status dataset } } }"}'
→ 15 observations — 5 years x 3 datasets. 2024 reads 4190.01 (ecodb-imf-weo), 4190.008 (imf-weo/2026-04) and 4190.00818835857 (wb-wdi/2026-07-13): same number, three precisions. Add dataset:"ecodb-imf-weo" to keep one
curl -s https://q.ecolod.org/graphql -H 'Content-Type: application/json' \
-d '{"query":"{ ranking(indicator:\"gdp-nominal-usd\", limit:5){ country { iso3 } value year } }"}'
→ USA 30767.08 / CHN 19626.25 / DEU 5048.06 / JPN 4435.16 / GBR 4003.02, all year 2025 (USD billions). ranking defaults to the ecodb-imf-weo portal dataset — see the Query.ranking description in the SDL for why
curl -s https://q.ecolod.org/graphql -H 'Content-Type: application/json' \
-d '{"query":"{ indicator(id:\"NGDPD\"){ slug notation unit label(lang:\"ja\") } }"}'
→ slug = gdp-nominal-usd, notation = NGDPD, unit = usd-billion-current, label = 名目GDP (USドル). indicator(id:) takes either the slug or the skos:notation; every indicator carries prefLabels in all ten portal languages
curl -s https://q.ecolod.org/graphql -H 'Content-Type: application/json' \
-d '{"query":"{ search(text:\"失業\"){ label lang indicator { slug } } }"}'
→ 2 hits: 失業率@ja -> unemployment-rate, 若年失業率 (15-24歳)@ja -> youth-unemployment
curl -s https://q.ecolod.org/graphql -H 'Content-Type: application/json' \
-d '{"query":"{ datasets { uri title license issued } }"}'
→ 3 datasets. ecodb-imf-weo (the portal series, 127245 observations) is referenced by its observations but carries no dcterms metadata, so its title/license come back null; imf-weo/2026-04 = "IMF World Economic Outlook (April 2026 edition)" and wb-wdi/2026-07-13 = "World Bank World Development Indicators" (CC BY 4.0)
The same (country, indicator, year) can carry up to three observations, because the store unions the portal's own series with the IMF and World Bank feeds it is built from:
ecodb-imf-weo — the series the ecolod.org country pages render; ranking defaults to itimf-weo/2026-04 — IMF World Economic Outlook, vintaged (October editions will sit alongside, not overwrite)wb-wdi/2026-07-13 — World Bank World Development Indicators, full precisionseries and observations return all three, each labelled with its
dataset; pass dataset: to scope to one. Short forms
("wb-wdi/2026-07-13") and full IRIs are both accepted, and an unresolvable value
is an error rather than an empty list.
8 (introspection exempt)60limit: 200 (default 20)Lists are batched per resolution level, so
countries(limit:200){ indicators { label } } costs four upstream queries, not four
hundred. A query that still exceeds the call budget fails loudly rather than truncating.
"""
GraphQL facade over the ecolod.org economic-statistics graph (read-only).
Country URIs are https://ecolod.org/country/{ISO-3166-1 alpha-3}; indicator
URIs are https://ecolod.org/concept/indicator/{slug}. Every field is translated
into a bounded SPARQL SELECT and run against the same vetted /sparql path.
The store is a UNION of three qb:DataSets, so one (country, indicator, year)
triple of coordinates can carry up to three observations that differ in
precision and vintage:
* https://ecolod.org/data/dataset/ecodb-imf-weo (the portal's own series)
* https://ecolod.org/data/dataset/imf-weo/2026-04 (IMF WEO, vintaged)
* https://ecolod.org/data/dataset/wb-wdi/2026-07-13 (World Bank WDI)
Series observations are returned from ALL of them, each labelled with its
dataset; pass `dataset:` to scope to one. Short forms are accepted
("ecodb-imf-weo", "imf-weo/2026-04", "wb-wdi/2026-07-13") as well as full IRIs;
an unresolvable value is an error, never a silently empty result.
"""
type Query {
"""
One country by ISO-3166-1 alpha-3 code; null when the graph holds no observation for it.
"""
country(iso3: String!): Country
"""Every country that has at least one observation, ordered by URI."""
countries(limit: Int = 50, offset: Int = 0): [Country!]!
"""
One indicator by slug (e.g. "gdp-nominal-usd"), by skos:notation (e.g. "NGDPD"), or by its full concept URI; null if unknown.
"""
indicator(id: String!): Indicator
"""Every indicator concept, ordered by URI."""
indicators: [Indicator!]!
"""
The time series for one (country, indicator) pair. Null only when the country
or the indicator itself is unknown — a known pair with no data returns a
Series whose observations list is empty, so \"bad arguments\" stays
distinguishable from \"no data\". `from`/`to` are inclusive year bounds and
become the defaults for the nested `observations` field.
"""
series(country: String!, indicator: String!, dataset: String, from: Int, to: Int): Series
"""
Countries ranked by an indicator, highest value first.
Semantics: within ONE dataset (default: the ecodb-imf-weo portal dataset),
take the latest year that has an actual — non-forecast, eco:obsStatus "A" —
observation, then order that year's values descending. Scoping to a single
dataset is not a nicety: without it every economy would appear once per
source, and the three sources disagree in the last digits. The default
reproduces exactly what the ecolod.org portal pages show.
"""
ranking(indicator: String!, limit: Int = 20, dataset: String): [RankingEntry!]!
"""
Case-insensitive substring search over indicator prefLabel/altLabel in any of the 10 portal languages.
"""
search(text: String!, lang: String, limit: Int = 20): [SearchHit!]!
"""
Every dataset present in the store, ordered by URI. Metadata fields are null for datasets the store describes only by reference.
"""
datasets: [Dataset!]!
}
type Country {
"""ISO-3166-1 alpha-3 code (e.g. "JPN")."""
iso3: String!
"""Full country URI."""
uri: String!
"""
Country name in a language. Resolution order: the asked language, then
English, then the ISO3 code itself. The current bake asserts no triples at all
about country resources, so this returns the code in practice; the label rungs
activate automatically if a future bake adds them.
"""
name(lang: String = "en"): String
"""
All country labels with their language tags (empty in the current bake — see `name`).
"""
names: [Label!]!
"""
Indicators that have at least one observation for this country, ordered by URI.
"""
indicators(limit: Int = 30): [Indicator!]!
}
type Indicator {
"""Local slug (e.g. "gdp-nominal-usd")."""
slug: String!
"""Full indicator concept URI."""
uri: String!
"""skos:notation — the source's own code (e.g. "NGDPD")."""
notation: String
"""
Local name of the eco:defaultUnit concept (e.g. "usd-billion-current").
"""
unit: String
"""skos:prefLabel for a language (default en), falling back to English."""
label(lang: String = "en"): String
"""
All skos:prefLabel values with their language tags (10 portal languages).
"""
labels: [Label!]!
"""skos:definition for a language (default en), falling back to English."""
definition(lang: String = "en"): String
}
type Label {
value: String!
"""BCP-47 language tag, or "" for an untagged literal."""
lang: String!
}
type Series {
country: Country!
indicator: Indicator!
"""
Observations, ordered by (year, dataset). Arguments override the defaults
inherited from the enclosing `series(...)` call: `from`/`to` are inclusive
year bounds, `status` is "A" (outturn) or "F" (forecast), `dataset` scopes to
one source.
"""
observations(from: Int, to: Int, status: String, dataset: String): [Observation!]!
}
type Observation {
"""Calendar year (eco:timePeriod, an xsd:gYear, parsed to an Int)."""
year: Int!
"""eco:obsValue."""
value: Float!
"""eco:obsStatus — "A" = actual/outturn, "F" = forecast."""
status: String!
"""IRI of the qb:DataSet this number came from."""
dataset: String!
}
type RankingEntry {
country: Country!
value: Float!
year: Int!
status: String!
}
type SearchHit {
"""The matched label value."""
label: String!
"""Language tag of the matched label ("" if untagged)."""
lang: String!
indicator: Indicator!
}
type Dataset {
uri: String!
title: String
description: String
license: String
issued: String
}