Skip to content

Commit feb050d

Browse files
author
Alfiya Tarasenko
committed
Add new geocode and reverse geocode examples
1 parent ab247ed commit feb050d

9 files changed

Lines changed: 1541 additions & 0 deletions

File tree

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Welcome to the **Geoapify Location Platform Code Samples** repository! This proj
1414

1515
* [Batch Geocoding with Rate Limiting](#nodejs-batch-geocoding-with-rate-limiting)
1616
* [Batch Reverse Geocoding](#nodejs-batch-reverse-geocoding)
17+
* [Geocoding CLI from CSV with Retries](#nodejs-geocoding-cli-from-csv-with-retries)
18+
* [Reverse Geocoding CLI from CSV](#nodejs-reverse-geocoding-cli-from-csv)
1719

1820
### Python
1921

@@ -95,6 +97,53 @@ Reads coordinate pairs from a text file and uses the Geoapify Reverse Geocoding
9597

9698
---
9799

100+
101+
### Node.js: [Geocoding CLI from CSV with Retries](https://github.com/geoapify/maps-api-code-samples/tree/main/node/geocoding-cli-from-csv-with-retries)
102+
103+
**What it does:**
104+
Performs batch geocoding of addresses from a CSV file using the Geoapify API, with support for retries and configurable output formats.
105+
106+
**How it works:**
107+
Reads structured address data from a CSV file, builds address strings based on configurable column mappings, and sends requests to the Geoapify Geocoding API. It uses a rate limiter to stay within Free plan limits and includes retry logic for failed requests. The tool works both as a CLI and as a Node.js module.
108+
109+
**Key features:**
110+
111+
* Reads structured addresses from a CSV file (`Street`, `City`, `State`, `Country`, `PostalCode`)
112+
* Configurable column mapping and address formatting
113+
* Respects API rate limits (default: 5 requests per second)
114+
* Retries failed requests up to 3 times (configurable)
115+
* Supports multiple output formats: JSON, NDJSON, or console
116+
* Preserves input order and logs progress with timestamps
117+
* CLI and programmatic usage support
118+
119+
**APIs used:**
120+
121+
* [Geoapify Geocoding API](https://www.geoapify.com/geocoding-api/)
122+
* [@geoapify/request-rate-limiter](https://www.npmjs.com/package/@geoapify/request-rate-limiter)
123+
124+
---
125+
### Node.js: [Reverse Geocoding CLI from CSV](https://github.com/geoapify/maps-api-code-samples/tree/main/node/batch-reverse-geocode-from-csv)
126+
127+
**What it does:**
128+
Reads a list of geographic coordinates from a CSV file and performs batch reverse geocoding using the Geoapify Reverse Geocoding API.
129+
130+
**How it works:**
131+
Coordinates (`lat`, `lon`) are read from the CSV, then the script sends reverse geocoding requests with built-in rate limiting. It retries failed lookups and saves the output in NDJSON, JSON, or console format.
132+
133+
**Key features:**
134+
- Reads latitude/longitude pairs from a CSV file.
135+
- Customizable column mapping (e.g., `lat`, `lon` or `latitude`, `longitude`).
136+
- Respects rate limits using `@geoapify/request-rate-limiter`.
137+
- Supports automatic retry of failed requests (configurable max attempts).
138+
- Multiple output formats: `json`, `ndjson`, or `console`.
139+
- Preserves original row order and logs skipped/failed rows with reasons.
140+
141+
**APIs used:**
142+
- [Geoapify Reverse Geocoding API](https://www.geoapify.com/reverse-geocoding-api/)
143+
- [@geoapify/request-rate-limiter](https://www.npmjs.com/package/@geoapify/request-rate-limiter)
144+
145+
---
146+
98147
### Python: [Create Map Example](https://github.com/geoapify/maps-api-code-samples/tree/main/python/create-a-map)
99148

100149
**What it does:**
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
# Geoapify CLI Reverse Geocoder
2+
3+
A fast and flexible Node.js CLI tool for **batch reverse geocoding** geographic coordinates from CSV files using the [Geoapify Reverse Geocoding API](https://www.geoapify.com/reverse-geocoding-api/).
4+
5+
> 🧰 Use as a command-line utility or import as a Node.js module.
6+
7+
## 📚 Table of Contents
8+
9+
* [🚀 Features](#features)
10+
* [📦 Installation & Dependencies](#installation--dependencies)
11+
* [📁 Usage](#usage)
12+
* [📄 CSV Format](#csv-format)
13+
* [📝 Output Formats](#output-formats)
14+
* [⚠️ Error Handling & Fallbacks](#error-handling--fallbacks)
15+
* [📊 Sample Logs](#sample-logs)
16+
* [🔐 API Access Requirements](#api-access-requirements)
17+
18+
## Features
19+
20+
* Read coordinates from CSV files with customizable column mapping (`lat`, `lon`, etc.)
21+
* Built-in rate limiting using `@geoapify/request-rate-limiter` (default: 5 requests/second)
22+
* Automatically retries failed requests with configurable retry limits
23+
* Supports multiple output formats: JSON, NDJSON, or console
24+
* Preserves the original row order in the output
25+
* Skips invalid or empty coordinates with clear warning logs
26+
* Modular architecture with reusable utility modules
27+
* Can be used via CLI or as a Node.js module
28+
29+
## Installation & Dependencies
30+
31+
### Requirements
32+
33+
* **Node.js v18+** — Required for native `fetch()` support
34+
* **Geoapify API Key** — Get one at [https://www.geoapify.com](https://www.geoapify.com)
35+
36+
### Dependencies
37+
38+
This project uses the following NPM packages (already listed in `package.json`):
39+
40+
* [`@geoapify/request-rate-limiter`](https://www.npmjs.com/package/@geoapify/request-rate-limiter) – Handles request throttling
41+
* [`commander`](https://www.npmjs.com/package/commander) – CLI argument parsing
42+
* [`csv-parser`](https://www.npmjs.com/package/csv-parser) – Efficient CSV file parsing
43+
44+
### Install
45+
46+
In the project root, run:
47+
48+
```bash
49+
npm install
50+
```
51+
52+
## Usage
53+
54+
You can use the reverse geocoder as a **command-line tool** or as a **Node.js module** in your own scripts.
55+
56+
### Command Line Usage
57+
58+
#### Basic Example
59+
60+
```bash
61+
node reverse-geocoder.js -k YOUR_API_KEY -i coordinates.csv
62+
```
63+
64+
#### Full Example with All Options
65+
66+
```bash
67+
node reverse-geocoder.js \
68+
--api-key YOUR_API_KEY \
69+
--input coordinates.csv \
70+
--output results.ndjson \
71+
--rate-limit 5 \
72+
--output-format ndjson \
73+
--max-retries 3
74+
```
75+
76+
### CLI Options
77+
78+
| Option | Short | Description | Default |
79+
| ----------------- | ----- | ------------------------------------------------ | ------- |
80+
| `--api-key` | `-k` | **(Required)** Your Geoapify API key ||
81+
| `--input` | `-i` | **(Required)** Path to CSV file with coordinates ||
82+
| `--output` | `-o` | Path to write reverse geocoding results ||
83+
| `--rate-limit` | `-r` | Requests per second (RPS) | 5 |
84+
| `--output-format` | `-f` | Output format: `json`, `ndjson`, `console` | ndjson |
85+
| `--no-retry` | | Disable automatic retries for failed requests | false |
86+
| `--max-retries` | | Max retry attempts per failed request | 3 |
87+
88+
### Programmatic Usage
89+
90+
You can also import the geocoder into your own Node.js script:
91+
92+
```js
93+
const { reverseGeocodeCoordinates } = require('./reverse-geocoder');
94+
95+
async function main() {
96+
const results = await reverseGeocodeCoordinates({
97+
inputFile: 'coordinates.csv',
98+
outputFile: 'results.json',
99+
apiKey: 'YOUR_API_KEY',
100+
rateLimit: 5,
101+
outputFormat: 'json',
102+
retryFailedRequests: true,
103+
maxRetries: 3
104+
});
105+
106+
console.log(`Geocoded ${results.length} coordinates`);
107+
}
108+
```
109+
110+
## CSV Format
111+
112+
The input CSV file should contain latitude and longitude values for each point to be reverse geocoded.
113+
114+
### Default Column Names
115+
116+
By default, the script expects the following column headers:
117+
118+
```csv
119+
lat,lon
120+
40.7128,-74.0060
121+
34.0522,-118.2437
122+
41.8781,-87.6298
123+
```
124+
125+
### Custom Column Mapping
126+
127+
If your file uses different column names (e.g., `latitude`, `longitude`), you can change the mapping in the configuration section of the script or modify the CLI version to support dynamic mapping.
128+
129+
Only valid numeric values within the coordinate range will be processed:
130+
131+
* Latitude: -90 to 90
132+
* Longitude: -180 to 180
133+
134+
Invalid or empty coordinates will be skipped and logged with a warning.
135+
136+
## Output Formats
137+
138+
You can choose between three output formats using the `--output-format` (`-f`) option: `json`, `ndjson`, or `console`.
139+
140+
### JSON Format
141+
142+
A single JSON array containing all results. Recommended for smaller datasets or downstream systems expecting full structured data.
143+
144+
```json
145+
[
146+
{
147+
"success": true,
148+
"originalCoordinates": [40.7128, -74.0060],
149+
"result": {
150+
"formatted": "New York, NY 10007, United States of America",
151+
"city": "New York",
152+
"state": "New York",
153+
"country": "United States",
154+
"postcode": "10007",
155+
"lat": 40.7128,
156+
"lon": -74.0060
157+
},
158+
"originalRow": { "lat": "40.7128", "lon": "-74.0060" }
159+
}
160+
]
161+
```
162+
163+
### NDJSON Format (default)
164+
165+
Each result is written on a separate line as a standalone JSON object. Ideal for streaming or processing large datasets.
166+
167+
```
168+
{"success":true,"originalCoordinates":[40.7128,-74.0060],"result":{...}}
169+
{"success":false,"originalCoordinates":[null,null],"error":"Invalid coordinates"}
170+
```
171+
172+
### Console Output
173+
174+
If no `--output` path is specified and `--output-format` is set to `console`, results are printed to stdout.
175+
176+
## Error Handling & Fallbacks
177+
178+
The script includes robust mechanisms to handle common issues and ensure consistent results, even when individual lookups fail.
179+
180+
### What’s Handled:
181+
182+
* **Empty or invalid coordinates**
183+
Rows with missing or invalid `lat`/`lon` values are skipped and logged with a warning.
184+
185+
* **Network or API errors**
186+
Failures due to timeouts, DNS errors, or API availability are retried (up to `--max-retries` times).
187+
188+
* **No results from API**
189+
If no address is found for given coordinates, the result is logged with a descriptive error and included in the output with `"success": false`.
190+
191+
* **Rate limiting (HTTP 429)**
192+
Automatically throttled using the `@geoapify/request-rate-limiter` to avoid exceeding Geoapify API limits.
193+
194+
* **File read/write errors**
195+
Clear fatal errors are logged if input/output files are inaccessible or invalid.
196+
197+
### Output Consistency:
198+
199+
* Output files (JSON or NDJSON) always match the order of the original input rows.
200+
* Even failed entries preserve `originalRow` and `originalCoordinates` with an `error` field describing the issue.
201+
* Retry attempts are logged individually and limited by `--max-retries`.
202+
203+
## Sample Logs
204+
205+
The script logs each step with timestamps and clear status indicators. Below is an example log from a typical reverse geocoding run:
206+
207+
```
208+
[2025-07-14T12:00:00.000Z] INFO: Read 3 rows from coordinates.csv
209+
[2025-07-14T12:00:00.050Z] INFO: Starting reverse geocoding of 3 coordinates at 5 requests per second
210+
[2025-07-14T12:00:00.200Z] INFO: ✓ Geocoded: 40.7128,-74.0060
211+
[2025-07-14T12:00:00.400Z] INFO: ✓ Geocoded: 34.0522,-118.2437
212+
[2025-07-14T12:00:00.600Z] WARNING: ✗ Failed: Invalid coordinates - No results found
213+
[2025-07-14T12:00:00.700Z] INFO: Retry attempt 1/3: 1 failed requests...
214+
[2025-07-14T12:00:01.000Z] WARNING: ✗ Retry failed: Invalid coordinates - No results found
215+
[2025-07-14T12:00:01.100Z] INFO: Geocoding complete: 2 successful, 1 failed
216+
[2025-07-14T12:00:01.200Z] INFO: Results written to results.ndjson
217+
```
218+
219+
### Log Levels
220+
221+
* `INFO` — Standard messages: file read, request success, summary
222+
* `WARNING` — Non-fatal issues: failed lookups, skipped rows, retries
223+
* `ERROR` — Critical problems that stop the script: file not found, invalid input, API key missing
224+
225+
## API Access Requirements
226+
227+
This tool uses the [Geoapify Reverse Geocoding API](https://apidocs.geoapify.com/docs/geocoding/reverse-geocoding/).
228+
229+
### Requirements
230+
231+
* **Geoapify API Key** — Required for authenticating all requests
232+
Get your free API key at [geoapify.com](https://www.geoapify.com/get-started/)
233+
234+
* **Rate Limits**:
235+
236+
* Free plan allows up to **5 requests per second** (soft limit)
237+
* Daily quota: up to **3,000 requests per day** on the Free plan
238+
* Use the `--rate-limit` option to adjust request frequency
239+
240+
* **Node.js version**
241+
Requires **Node.js 18+** for native `fetch()` support
242+
243+
### Best Practices
244+
245+
* Avoid hardcoding your API key in public code repositories
246+
* Use environment variables or CLI flags (`--api-key`) to pass your key securely
247+
* If processing large datasets, consider:
248+
* Increasing `--rate-limit` with a paid plan
249+
* Splitting the workload into multiple batches
250+
* Scheduling jobs to avoid hitting daily limits
251+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "reverse-geocoder",
3+
"version": "1.0.0",
4+
"description": "Reverse geocode coordinates from CSV files using Geoapify API",
5+
"main": "reverse-geocoder.js",
6+
"scripts": {
7+
"start": "node reverse-geocoder.js -k 93b8e26606dd485183dcdab30f239f81 -i sample-coordinates.csv -o results.json -f json",
8+
"test": "echo \"Error: no test specified\" && exit 1"
9+
},
10+
"keywords": [
11+
"geocoding",
12+
"reverse-geocoding",
13+
"geoapify",
14+
"coordinates",
15+
"csv"
16+
],
17+
"author": "",
18+
"license": "MIT",
19+
"dependencies": {
20+
"@geoapify/request-rate-limiter": "^1.0.0",
21+
"commander": "^9.0.0",
22+
"csv-parser": "^3.0.0"
23+
}
24+
}

0 commit comments

Comments
 (0)