Skip to content

Commit 1b9b438

Browse files
author
Alfiya Tarasenko
committed
Add JS examples for Geocoding and Reverse Geocoding
1 parent 9e367f2 commit 1b9b438

10 files changed

Lines changed: 743 additions & 2 deletions

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
.vscode/settings.json
2-
.DS_Store
2+
.DS_Store
3+
**/**/node_modules
4+
**/**/package-lock.json
5+
**/**/results.json

README.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ This example demonstrates how to fetch **places data** from the Geoapify Places
146146
- [Asyncio](https://docs.python.org/3/library/asyncio.html), [Aiohttp](https://docs.aiohttp.org/)
147147

148148

149-
### **8. Python: [Route Planner Result Processor](https://github.com/geoapify/maps-api-code-samples/tree/main/python/route-planner)**
149+
### **10. Python: [Route Planner Result Processor](https://github.com/geoapify/maps-api-code-samples/tree/main/python/route-planner)**
150150

151151
#### **Description:**
152152
This example demonstrates how to process a request to the **Geoapify Route Planner API**, generate structured outputs for each agent, and visualize their assigned routes.
@@ -164,6 +164,42 @@ This example demonstrates how to process a request to the **Geoapify Route Plann
164164
- [Geoapify Routing API](https://www.geoapify.com/routing-api/)
165165
- [Folium Library](https://python-visualization.github.io/folium/)
166166

167+
168+
### **11. JavaScript(Node.js): [Batch Geocoding with Rate Limiting](https://github.com/geoapify/maps-api-code-samples/tree/main/javascript/geocoding-with-RPS-limit-respect)**
169+
170+
#### **Description:**
171+
This example demonstrates how to geocode a large number of addresses using the **Geoapify Geocoding API**, while automatically respecting API rate limits with the help of the [`@geoapify/request-rate-limiter`](https://www.npmjs.com/package/@geoapify/request-rate-limiter) package.
172+
173+
#### **Features:**
174+
- Reads addresses from a plain text file (`input.txt`), one per line.
175+
- Sends geocoding requests with a limit of **5 requests per second** (default for Free plan).
176+
- Outputs results to:
177+
- `results.json` — full API response per address.
178+
- Logs geocoding progress and errors in real-time.
179+
- Built with **ES modules**, `node-fetch`, and Geoapify’s official rate limiter.
180+
181+
#### **APIs Used:**
182+
- [Geoapify Geocoding API](https://www.geoapify.com/geocoding-api/)
183+
- [@geoapify/request-rate-limiter](https://www.npmjs.com/package/@geoapify/request-rate-limiter)
184+
185+
### **12. JavaScript(Node.js): [Batch Reverse Geocoding](https://github.com/geoapify/maps-api-code-samples/tree/main/javascript/reverse-geocoding-lat-lon-to-address)**
186+
187+
#### **Description:**
188+
This example demonstrates how to perform batch **reverse geocoding** using the **Geoapify Reverse Geocoding API**. It reads a list of latitude/longitude pairs from a text file, resolves them into addresses, and saves the output as structured JSON — all while respecting rate limits.
189+
190+
#### **Features:**
191+
- Reads coordinate pairs (`lat,lon`) from `input.txt`.
192+
- Calls the **Geoapify Reverse Geocoding API** for each location.
193+
- Uses [`@geoapify/request-rate-limiter`](https://www.npmjs.com/package/@geoapify/request-rate-limiter) to automatically respect the 5 RPS API limit.
194+
- Logs progress and handles errors gracefully.
195+
- Saves results to a `results.json` file in structured format.
196+
197+
#### **APIs Used:**
198+
- [Geoapify Reverse Geocoding API](https://www.geoapify.com/reverse-geocoding-api/)
199+
- [@geoapify/request-rate-limiter](https://www.npmjs.com/package/@geoapify/request-rate-limiter)
200+
- [node-fetch](https://www.npmjs.com/package/node-fetch)
201+
202+
167203
## Upcoming Code Samples
168204

169205
We plan to expand this repository with code samples in various programming languages, demonstrating different Geoapify APIs, including:
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# Geoapify Batch Geocoding Script
2+
3+
This Node.js script performs batch geocoding using the [Geoapify Geocoding API](https://www.geoapify.com/geocoding-api/) while **respecting rate limits** through the official [`@geoapify/request-rate-limiter`](https://www.npmjs.com/package/@geoapify/request-rate-limiter) package. It reads addresses from a text file, geocodes them, and writes the results to a JSON file.
4+
5+
## Highlights
6+
7+
- Uses [@geoapify/request-rate-limiter](https://www.npmjs.com/package/@geoapify/request-rate-limiter) to automatically respect Geoapify RPS limits
8+
- Reads addresses from `input.txt`
9+
- Outputs full results to `results.json`
10+
- Logs geocoding progress and errors
11+
- Built with ES Modules and `node-fetch`
12+
13+
## Requirements
14+
15+
- Node.js **v16+**
16+
- A [Geoapify API key](https://myprojects.geoapify.com)
17+
- The following dependencies:
18+
- [`@geoapify/request-rate-limiter`](https://www.npmjs.com/package/@geoapify/request-rate-limiter)
19+
- [`node-fetch`](https://www.npmjs.com/package/node-fetch)
20+
21+
## Install dependencies
22+
23+
All required dependencies are already listed in the `package.json` file.
24+
To install them, simply run:
25+
26+
```bash
27+
npm install
28+
```
29+
30+
## Usage
31+
32+
1. **Create `input.txt`**
33+
List one address per line:
34+
35+
```
36+
1600 Amphitheatre Parkway, Mountain View, CA
37+
1 Infinite Loop, Cupertino, CA
38+
```
39+
40+
2. Use your API key
41+
42+
Replace 'YOUR_API_KEY' with you Geoapify API key.
43+
44+
3. **Run the script**
45+
46+
```bash
47+
node geocode.js
48+
```
49+
50+
4. **View output**
51+
52+
- `results.json`: contains structured geocoding results
53+
54+
## Code Overview
55+
56+
### Powered by [`@geoapify/request-rate-limiter`](https://www.npmjs.com/package/@geoapify/request-rate-limiter)
57+
58+
This script relies on Geoapify's official rate limiter to stay within the Free plan's 5 requests per second. The package makes it easy to batch and throttle API calls without hitting limits.
59+
60+
### Key Components
61+
62+
- `readAddressesFromFile()` – Loads addresses from `input.txt`.
63+
- `createGeocodingRequest()` – Creates individual throttled fetch requests.
64+
- `geocodeBatch()` – Processes all addresses using `rateLimitedRequests()` with:
65+
- `limit: 5 RPS`
66+
- `batchSize: 10`
67+
- progress and batch logging
68+
- `saveToJSONFile()` – Writes structured results to disk.
69+
70+
## Output Example
71+
72+
A successful geocode result:
73+
74+
```json
75+
{
76+
"address": "North Oak Street, Bethalto, IL 62010, USA,",
77+
"result": {
78+
"datasource": {
79+
"sourcename": "openstreetmap",
80+
"attribution": "© OpenStreetMap contributors",
81+
"license": "Open Database License",
82+
"url": "https://www.openstreetmap.org/copyright"
83+
},
84+
"name": "North Oak Street",
85+
"country": "United States",
86+
"country_code": "us",
87+
"state": "Illinois",
88+
"county": "Madison County",
89+
"city": "Bethalto",
90+
"postcode": "62010",
91+
"street": "North Oak Street",
92+
"iso3166_2": "US-IL",
93+
"lon": -90.0421214,
94+
"lat": 38.9103244,
95+
"state_code": "IL",
96+
"result_type": "street",
97+
"formatted": "North Oak Street, Bethalto, IL 62010, United States of America",
98+
"address_line1": "North Oak Street",
99+
"address_line2": "Bethalto, IL 62010, United States of America",
100+
"timezone": {
101+
"name": "America/Chicago",
102+
"offset_STD": "-06:00",
103+
"offset_STD_seconds": -21600,
104+
"offset_DST": "-05:00",
105+
"offset_DST_seconds": -18000,
106+
"abbreviation_STD": "CST",
107+
"abbreviation_DST": "CDT"
108+
},
109+
"plus_code": "86CFWX65+45",
110+
"plus_code_short": "65+45 Bethalto, Madison County, United States",
111+
"rank": {
112+
"importance": 0.35334333333333334,
113+
"popularity": 1.6436670429679177,
114+
"confidence": 1,
115+
"confidence_city_level": 1,
116+
"confidence_street_level": 1,
117+
"match_type": "full_match"
118+
},
119+
"place_id": "518dddf41db28256c0591b608b8285744340f00102f90140194f0100000000c002049203104e6f727468204f616b20537472656574",
120+
"bbox": {
121+
"lon1": -90.0424917,
122+
"lat1": 38.909672,
123+
"lon2": -90.041749,
124+
"lat2": 38.9110236
125+
}
126+
}
127+
}
128+
```
129+
130+
If no result was found:
131+
132+
```json
133+
{
134+
"address": "Unknown Street",
135+
"error": "No result found"
136+
}
137+
```
138+
139+
## Read More
140+
141+
- [Geoapify Geocoding API Documentation](https://www.geoapify.com/geocoding-api/)
142+
- [@geoapify/request-rate-limiter on npm](https://www.npmjs.com/package/@geoapify/request-rate-limiter)
143+
- [node-fetch Documentation](https://www.npmjs.com/package/node-fetch)
144+
- [Geoapify Developer Portal](https://apidocs.geoapify.com/)
145+
- [Rate Limiting and Batch Request Patterns (Blog)](https://www.geoapify.com/how-to-avoid-429-too-many-requests-with-api-rate-limiting/)
146+
147+
For advanced use cases like CSV input/output, asynchronous job batching, or fallback handling, check the [Geoapify GitHub Examples](https://github.com/geoapify/maps-api-code-samples).
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import fetch from 'node-fetch';
2+
import RequestRateLimiter from '@geoapify/request-rate-limiter';
3+
import fs from 'fs/promises';
4+
5+
async function readAddressesFromFile(filename = 'input.txt') {
6+
try {
7+
const data = await fs.readFile(filename, 'utf-8');
8+
return data
9+
.split('\n')
10+
.map(line => line.trim())
11+
.filter(line => line.length > 0);
12+
} catch (err) {
13+
console.error(`❌ Failed to read ${filename}:`, err.message);
14+
return [];
15+
}
16+
}
17+
18+
const API_KEY = "YOUR_API_KEY";
19+
const GEOCODING_API_URL = 'https://api.geoapify.com/v1/geocode/search?limit=1&format=json';
20+
21+
const createGeocodingRequest = (address) => {
22+
return async () => {
23+
try {
24+
const url = `${GEOCODING_API_URL}&text=${encodeURIComponent(address)}&apiKey=${API_KEY}`;
25+
const response = await fetch(url);
26+
if (!response.ok) {
27+
return { address, error: `HTTP error ${response.status}: ${response.statusText}` };
28+
}
29+
30+
const data = await response.json();
31+
if (data.results && data.results.length > 0) {
32+
return { address, result: data.results[0] };
33+
} else {
34+
return { address, error: 'No result found' };
35+
}
36+
} catch (err) {
37+
return { address, error: err.message };
38+
}
39+
};
40+
};
41+
42+
async function geocodeBatch(addresses) {
43+
const requests = addresses.map(createGeocodingRequest);
44+
45+
const options = {
46+
batchSize: 10,
47+
onProgress: (progress) => {
48+
console.log(`Progress: ${progress.completedRequests}/${progress.totalRequests}`);
49+
},
50+
onBatchComplete: (batch) => {
51+
console.log(`Batch completed (${batch.results.length}):`);
52+
batch.results.forEach(r => {
53+
console.log(r.result
54+
? `✅ ${r.address} → (${r.result.lat}, ${r.result.lon})`
55+
: `❌ ${r.address}${r.error}`);
56+
});
57+
}
58+
};
59+
60+
try {
61+
const results = await RequestRateLimiter.rateLimitedRequests(requests, 5, 1000, options);
62+
console.log('\n✅ All requests completed.');
63+
64+
return results;
65+
} catch (err) {
66+
console.error('❌ Error during batch geocoding:', err);
67+
}
68+
}
69+
70+
async function saveToJSONFile(results, filename = 'results.json') {
71+
const json = JSON.stringify(results, null, 2);
72+
await fs.writeFile(filename, json, 'utf-8');
73+
console.log(`✅ Results saved to ${filename}`);
74+
}
75+
76+
const addresses = await readAddressesFromFile();
77+
const results = await geocodeBatch(addresses);
78+
await saveToJSONFile(results);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
North Oak Street, Bethalto, IL 62010, USA,
2+
2809 College Avenue, Alton, IL 62002, USA,
3+
1 Lock and Dam Way, Alton, IL 62002, USA,
4+
40 West Ferguson Avenue, Wood River, IL 62095, USA,
5+
Illinois Route 111, Roxana, IL 62084, USA,
6+
715 North Main Street, Edwardsville, IL 62025, USA,
7+
620 Saint Louis Street, Edwardsville, IL 62025, USA,
8+
409 South Buchanan Street, Edwardsville, IL 62025, USA,
9+
722 Holyoake Road, Edwardsville, IL 62025, USA,
10+
1 Lewis and Clark Trail, Hartford, IL 62048, USA,
11+
Woodcrest Lane, Hazelwood, MO 63042, USA,
12+
14301 Creve Coeur Airport Road, Maryland Heights, MO 63146, USA,
13+
Plum Street, Collinsville, IL 62234, USA,
14+
4600 Labadie Avenue, St. Louis, MO 63115, USA,
15+
30 Ramey Street, Collinsville, IL 62234, USA,
16+
2505 Saint Louis Avenue, St. Louis, MO 63106, USA,
17+
2223 Saint Louis Avenue, St. Louis, MO 63106, USA,
18+
Westmoreland Avenue, Clayton, MO 63105, USA,
19+
1 Forsyth Boulevard, St. Louis, MO 63130, USA,
20+
5700 Lindell Boulevard, St. Louis, MO 63018, USA,
21+
650 Maryville University Drive, Town and Country, MO 63141, USA,
22+
4652 Maryland Avenue, St. Louis, MO 63108, USA,
23+
478 Covenat Lane, Creve Coeur, MO 63141, USA,
24+
3750 Washington Boulevard, St. Louis, MO 63108, USA,
25+
1 Fine Arts Drive, St. Louis, MO 63110, USA,
26+
2716 Doctor Martin Luther King Drive, St. Louis, MO 63106, USA,
27+
3441 Olive Street, St. Louis, MO 63103, USA,
28+
2660 Delmar Boulevard, St. Louis, MO 63103, USA,
29+
3415 Olive Street, St. Louis, MO 63103, USA,
30+
750 North 16th Street, St. Louis, MO 63103, USA,
31+
1508 Locust Street, St. Louis, MO 63103, USA,
32+
720 North 2nd Street, St. Louis, MO 63102, USA,
33+
615 Washington Avenue, St. Louis, MO 63101, USA,
34+
5050 Oakland Avenue, St. Louis, MO 63110, USA,
35+
1315 Chestnut Street, St. Louis, MO 63103, USA,
36+
1005 Pennsylvania Avenue, East St. Louis, IL 62201, USA,
37+
411 Locust Street, St. Louis, MO 63102, USA,
38+
1101 Macklind Avenue, St. Louis, MO 63110, USA,
39+
11 North 4th Street, St. Louis, MO 63101, USA,
40+
Gateway Arch Trail, St. Louis, MO 63102, USA,
41+
283 Lamp & Lantern Village, Town and Country, MO 63017, USA
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "geocoding-with-rps-limit-respect",
3+
"version": "1.0.0",
4+
"main": "geocode.js",
5+
"type": "module",
6+
"scripts": {
7+
"start": "node geocode.js",
8+
"test": "echo \"Error: no test specified\" && exit 1"
9+
},
10+
"keywords": [
11+
"geocoding",
12+
"geoapify",
13+
"batch",
14+
"rate-limit",
15+
"node.js",
16+
"api"
17+
],
18+
"author": "Geoapify",
19+
"license": "MIT",
20+
"description": "",
21+
"dependencies": {
22+
"@geoapify/request-rate-limiter": "^1.0.1",
23+
"node-fetch": "^3.3.2"
24+
}
25+
}

0 commit comments

Comments
 (0)