A serverless RESTful API for querying and analyzing the NASA Meteorite Landings dataset.
Built on Cloudflare Workers and developed with Wrangler.
The project is designed to run entirely on serverless infrastructure, with optimized processing and algorithms that require minimal resources. As a result, it performs well on small and medium-sized datasets and under moderate traffic volumes.
- 🚀 Key features
- 🌐 API access
- 📚 Available endpoints
- 🖥️ Developer documentation and datasets
- >_ Python CLI for custom datasets
- ⚖️ License
- 🎯 Author
- CORS enabled — use the API directly from your website or any other project.
- No sign-up required — no account creation, credit card, or personal data needed.
- Rate limiting — protection against abuse with request throttling.
- Privacy-conscious — built with privacy in mind, considering GDPR principles where applicable.
- Advanced search — multiple filters for precise queries.
- Serverless optimized — lightweight, high-performance architecture.
| Endpoint | Rate limit | Maintainer | Dataset |
|---|---|---|---|
| https://meteorites.nde-code.workers.dev/ | 1 req/IP/s | Me | meteorites_small.json |
The rate-limiting system temporarily processes IP addresses, which are pseudonymized using a hash combined with a secret salt before being used for rate limiting. It provides burst protection, and the resulting hashed value is temporarily stored in Cloudflare Workers Cache. The hashed value is retained only for the duration required to enforce these limits and is automatically removed afterward.
📡 Check the status page if you experience latency or other issues while using the public online instance.
Parameters defined in config.ts:
# Absolute upper limit; exceeding this value triggers an error:
MAX_RANDOM_METEORITES: 1000
# Maximum number of results the search system will return:
MAX_RETURNED_SEARCH_RESULTS: 500
# Smallest allowed radius for any computation or query:
MIN_RADIUS: 1
# Largest allowed radius to prevent overly broad or costly searches:
MAX_RADIUS: 2500
# Default number used when no 'count' value is provided:
DEFAULT_RANDOM_NUMBER_OF_METEORITES: 100Note: these limits may be updated, so check the repository regularly to stay informed.
Search meteorites by multiple criteria: name, classification, date, mass, and geographic location.
Query parameters
| Parameter | Type | Description |
|---|---|---|
recclass |
string | Meteorite classification |
fall |
string | Fall status: Fell or Found |
year |
number | Exact year of fall or discovery |
minYear |
number | Minimum year |
maxYear |
number | Maximum year |
mass |
number | Exact mass (grams) |
minMass |
number | Minimum mass (grams) |
maxMass |
number | Maximum mass (grams) |
centerLatitude |
number | Center latitude (required with radius) |
centerLongitude |
number | Center longitude (required with radius) |
radius |
number | Search radius in km (min: MIN_RADIUS, max: MAX_RADIUS) (required with coordinates) |
limit |
number | Maximum results (min: 1, max: MAX_RETURNED_SEARCH_RESULTS) |
Note on geographic precision: distance calculation uses equirectangular approximation (optimized for performance). Highly accurate for local/regional queries (< 1000–1500 km). For larger radii, especially at high latitudes, minor distortions may occur compared to geodesic (Haversine) calculations.
Parameter behavior:
- Unknown parameters are ignored.
- Invalid numeric parameters are treated as absent (e.g.,
year=abc). - Conflicting filters return
400error (e.g.,yearwithminYear/maxYear). - Geographic search requires all three:
centerLatitude,centerLongitude, andradius. limitis automatically capped atMAX_RETURNED_SEARCH_RESULTS.
Response codes:
| Code | Description |
|---|---|
200 |
Success (may return empty set) |
400 |
Missing or invalid parameters |
429 |
Rate limit exceeded |
500 |
Server error (config or environment) |
503 |
Service unavailable (cache empty/loading) |
Example request:
curl "https://meteorites.nde-code.workers.dev/search?year=2013"Example response:
{
"success": {
"count": 1,
"meteorites": [
{
"id": "57165",
"name": "Chelyabinsk",
"recclass": "LL5",
"mass": 100000,
"fall": "Fell",
"year": 2013,
"latitude": 54.81667,
"longitude": 61.11667
}
]
}
}Retrieve detailed information about a single meteorite by id or name.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Unique meteorite identifier |
name |
string | Exact meteorite name (case-insensitive, normalized) |
Note: provide either
idorname, but not both. Providing neither will result in a400error.
Response codes:
| Code | Description |
|---|---|
200 |
Meteorite found |
400 |
Missing/invalid parameters or both provided |
404 |
No matching meteorite |
429 |
Rate limit exceeded |
500 |
Server error |
503 |
Service unavailable |
Example requests:
By ID:
curl "https://meteorites.nde-code.workers.dev/get?id=12345"By name:
curl "https://meteorites.nde-code.workers.dev/get?name=Kopjes%20Vlei"Example response:
{
"success": {
"meteorite": {
"id": "12345",
"name": "Kopjes Vlei",
"recclass": "Iron, IIAB",
"mass": 13600,
"fall": "Found",
"year": 1914,
"latitude": -29.3,
"longitude": 21.15
}
}
}Get a random set of meteorites.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
count |
number | Number of meteorites (default: DEFAULT_RANDOM_NUMBER_OF_METEORITES, max: MAX_RANDOM_METEORITES) |
Note: invalid
countreturns the default number.
Response codes:
| Code | Description |
|---|---|
200 |
Success |
400 |
Invalid count parameter |
429 |
Rate limit exceeded |
500 |
Server error |
503 |
Service unavailable |
Example request:
curl "https://meteorites.nde-code.workers.dev/random?count=3"Example response:
{
"success": {
"count": 3,
"meteorites": [
{
"id": "14764",
"name": "Mabwe-Khoywa",
"recclass": "L5",
"mass": 540,
"fall": "Fell",
"year": 1937,
"latitude": 19,
"longitude": 97
},
{
"id": "11442",
"name": "Guibga",
"recclass": "L5",
"mass": 288,
"fall": "Fell",
"year": 1972,
"latitude": 13.5,
"longitude": -0.68333
},
{
"id": "8671",
"name": "Elephant Moraine 90262",
"recclass": "L6",
"mass": 9.2,
"fall": "Found",
"year": 1990,
"latitude": -76.28752,
"longitude": 156.44737
}
]
}
}Get aggregated statistics: year ranges, mass stats, classifications, and geolocation info.
Response fields:
| Field | Type | Description |
|---|---|---|
meteorites_count |
number | Total number of meteorites |
min_year, max_year |
string | Earliest and latest year |
min_mass_g, max_mass_g |
number | Minimum/maximum mass (grams) |
avg_mass_g |
number | Average mass (2 decimal places) |
years |
string[] | Sorted list of all available years |
years_distribution |
object | Frequency by year |
recclasses |
string[] | List of unique classifications |
recclasses_distribution |
object | Frequency by classification |
geolocated_count |
number | Meteorites with valid coordinates |
fall_counts |
object | Breakdown of fell vs found |
Note: some meteorites have a mass of 0 grams. This reflects specific cases (extreme alteration, fossilization, missing fragments) and is not an error.
Response codes:
| Code | Description |
|---|---|
200 |
Success |
429 |
Rate limit exceeded |
500 |
Server error |
503 |
Service unavailable |
Example request:
curl "https://meteorites.nde-code.workers.dev/stats"Example response:
{
"success": {
"meteorites_count": 8500,
"min_year": "860",
"max_year": "2013",
"min_mass_g": 0.1,
"max_mass_g": 60000000,
"avg_mass_g": 68231.78,
"years": [
"860",
"920",
"1399",
"1490",
"1491",
...
],
"years_distribution": {
"860": 1,
"920": 1,
"1399": 1,
"1490": 1,
"1491": 1,
...
},
"recclasses": [
"Acapulcoite",
"Achondrite-ung",
"Angrite",
"Aubrite",
...
],
"recclasses_distribution": {
"L6": 1616,
"H5": 1461,
"H6": 749,
"L5": 653,
"H4": 637,
...
},
"geolocated_count": 8500,
"fall_counts": {
"fell": 1095,
"found": 7405
}
}
}Check API integrity and status, including cache and indexes.
Response fields:
| Field | Type | Description |
|---|---|---|
status |
string | Overall status: "healthy" or "unhealthy" |
timestamp |
string | ISO 8601 timestamp of check |
checks |
object | Details of internal components |
message |
string | Status summary message |
Internal checks detail:
| Check | Description |
|---|---|
cache_ready |
Main cache fully loaded |
meteorites_count |
Total meteorites in memory |
shuffled_meteorites_count |
Meteorites available for /random |
stats_available |
Pre-computed statistics ready |
by_id_index_size |
Entries in ID lookup index |
by_name_index_size |
Entries in name lookup index |
Note: a
503response indicates at least one check failed (cache not ready, empty indexes, etc.).
Response codes:
| Code | Description |
|---|---|
200 |
All systems operational |
503 |
One or more checks failed |
Example request:
curl "https://meteorites.nde-code.workers.dev/health"Example response (healthy):
{
"status": "healthy",
"timestamp": "2026-04-23T12:14:49.107Z",
"checks": {
"cache_ready": true,
"meteorites_count": 8500,
"shuffled_meteorites_count": 8500,
"stats_available": true,
"by_id_index_size": 8500,
"by_name_index_size": 8500
},
"message": "All endpoints are functional."
}For setup, configuration, and deployment using the Wrangler CLI, see the developer guide.
The API is optimized for performance with limited resources. Choose datasets based on your needs:
| Dataset | Size | Description |
|---|---|---|
meteorites_complete.json |
~33k entries | Complete dataset (unfiltered) |
meteorites_medium.json |
~15k entries | Reduced via grid filtering |
meteorites_small.json |
~8.5k entries | Default, reduced via grid filtering |
Note: these datasets have been cleaned up (see the CLI documentation and the
--clean-upargument for details).
Medium dataset, generated via:
python compiler.py --input "data/meteorites.csv" --output "data/meteorites_medium.json" \
--grid 0.00085 --limit 15000 --clean-up --minifySmall dataset, generated via:
python compiler.py --input "data/meteorites.csv" --output "data/meteorites_small.json" \
--grid 0.014 --limit 8500 --clean-up --minifyRequires Python 3.10+ (no external dependencies).
Available options:
| Argument | Description |
|---|---|
--input |
Path to meteorites.csv (required) |
--output |
Path to the output JSON file (required) |
--grid |
Grid cell size in degrees. If > 0, keeps at most one meteorite per grid cell |
--limit |
Maximum number of records. 0 = unlimited. Processing stops once the limit is reached |
--clean-up |
Remove records with missing or invalid location data and normalize empty fields (recommended) |
--minify |
Minify the output JSON by removing unnecessary whitespace |
--debug |
Verbosity level: 0 (silent), 1 (info), 2 (verbose) |
Usage:
Navigate to the directory containing compiler.py and run:
python compiler.py --input "data/meteorites.csv" --output "data/my_db.json" --clean-up --debug 2For help:
python compiler.py --helpNote: the
--gridoption creates visually optimized datasets (one meteorite per cell) but loses the original statistical distribution.
This project is licensed under the Apache License v2.0.
Created and maintained by Nde-Code.
Don't hesitate to open an issue or a pull request if you have any questions or would like to contribute.