npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

geojson-getter

v1.0.0

Published

Resolve GeoJSON for OpenStreetMap relations via OSM relation ID or Wikidata ID

Downloads

157

Readme

geojson-getter

A TypeScript library that resolves GeoJSON for OpenStreetMap relations, either directly by OSM relation ID or via a Wikidata ID lookup.

How it works

  1. Wikidata lookup — given a Wikidata ID, fetches the entity and extracts the OSM relation ID from the P402 statement
  2. Overpass query — fetches the relation geometry from the Overpass API using [out:json];relation(id);out geom qt;
  3. GeoJSON conversion — converts the Overpass response to GeoJSON using osmtogeojson

Multiple Overpass mirrors are tried in sequence; the first successful response is used. All functions return a Result type — errors never throw, and every failure mode is typed.

Fair use

This library queries the Wikidata REST API and public Overpass API mirrors. Both are free, community-funded services — please use them responsibly:

  • Cache results wherever possible. Relation geometry rarely changes; re-fetching on every request is unnecessary load on shared infrastructure.
  • Set a meaningful userAgent that identifies your application and includes a contact URL. Instance operators use this to reach you if your usage causes issues.
  • Do not use this library for bulk or batch processing without running your own Overpass instance. Public mirrors are not intended for high-volume automated queries.
  • Respect rate limits. A 429 response means you are sending too many requests. Back off and retry with delays rather than switching mirrors aggressively.

Each Overpass mirror operates independently and may have its own usage policy — check the terms of the specific mirror you are using. For large-scale usage, consider hosting your own Overpass instance using overpass-api.de's Docker image and passing it via overpassApiUrls.

Wikidata API usage policy: https://www.wikidata.org/wiki/Wikidata:Data_access
Overpass API: https://wiki.openstreetmap.org/wiki/Overpass_API

Usage

By OSM relation ID

import { getGeojsonFromOsmRelationId } from 'geojson-getter';

const result = await getGeojsonFromOsmRelationId({
  osmId: 62484,
  userAgent: 'myapp/1.0 (https://github.com/myorg/myrepo)',
});

if (!result.ok) {
  switch (result.error.type) {
    case 'invalid_osm_id': // bad input
    case 'no_elements': // relation exists but has no geometry
    case 'overpass_failed': // all mirrors exhausted; result.error.attempts has per-URL details
    case 'geojson_conversion_failed':
  }
  return;
}

console.log(result.value); // GeoJSON FeatureCollection

Custom Overpass mirrors

const result = await getGeojsonFromOsmRelationId({
  osmId: 62484,
  userAgent: 'myapp/1.0 (https://github.com/myorg/myrepo)',
  overpassApiUrls: [
    'https://overpass-api.de/api/interpreter',
    'https://my-own-mirror.example.com/api/interpreter',
  ],
});

By Wikidata ID

import { getGeojsonFromWikidataId } from 'geojson-getter';

const result = await getGeojsonFromWikidataId({
  wikidataId: 'Q3974',
  userAgent: 'myapp/1.0 (https://github.com/myorg/myrepo)',
});

if (!result.ok) {
  switch (result.error.type) {
    case 'no_osm_id_for_wikidata': // entity exists but has no P402 statement
    case 'wikidata_failed': // Wikidata request failed
    case 'no_elements':
    case 'overpass_failed':
    case 'geojson_conversion_failed':
  }
  return;
}

console.log(result.value); // GeoJSON FeatureCollection

Error types

All functions return a Result discriminated union — check result.ok before accessing result.value (success) or result.error (failure).

type GeojsonError =
  | { type: 'invalid_osm_id'; osmId: string }
  | { type: 'no_osm_id_for_wikidata'; wikidataId: string }
  | { type: 'wikidata_failed'; error: WikidataError }
  | { type: 'overpass_failed'; attempts: OverpassAttempt[] }
  | { type: 'geojson_conversion_failed'; cause: unknown }
  | { type: 'no_elements'; osmId: string };

type WikidataError =
  | { type: 'network_error'; cause: unknown }
  | { type: 'http_error'; status: number };

type OverpassAttempt = {
  url: string;
  error:
    | { type: 'network_error'; cause: unknown }
    | { type: 'http_error'; status: number }
    | { type: 'overpass_error'; cause: unknown };
};

OverpassAttempt contains the URL that was tried and the specific error (network_error, http_error, or overpass_error) so callers have full visibility into which mirrors failed and why.

User agent

Overpass mirrors require a descriptive User-Agent to identify your application. The conventional format is:

appname/version (contact-or-url)

Omitting it or using a generic value will result in 403 or 429 responses from most mirrors.

Default Overpass mirrors

Requests are tried in order against:

  • https://overpass.private.coffee/api/interpreter
  • https://maps.mail.ru/osm/tools/overpass/api/interpreter
  • https://overpass-api.de/api/interpreter

Development

Setup

npm install

Testing

# run once
npm test

# watch mode
npm run test:watch

# with coverage
npx vitest run --coverage

No tests make real HTTP requests. Fetch and module dependencies are fully mocked.