@xenterprises/fastify-xgeocode 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +144 -0
- package/QUICK_START.md +126 -0
- package/README.md +126 -0
- package/package.json +40 -0
- package/src/xGeocode.js +363 -0
- package/test/xGeocode.test.js +901 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [1.0.0] - 2025-12-29
|
|
6
|
+
|
|
7
|
+
### ✅ Initial Release - Production Ready
|
|
8
|
+
|
|
9
|
+
#### Features
|
|
10
|
+
- ✅ Easy Geocodio API integration for Fastify
|
|
11
|
+
- ✅ Get latitude/longitude from zip codes (5-digit and ZIP+4 formats)
|
|
12
|
+
- ✅ Retrieve address components (city, county, state, country)
|
|
13
|
+
- ✅ Optional plugin activation (can be disabled with `active: false`)
|
|
14
|
+
- ✅ Comprehensive error handling with environment-aware messages
|
|
15
|
+
- ✅ Input validation for zip code formats
|
|
16
|
+
- ✅ Full test coverage (14 tests)
|
|
17
|
+
- ✅ Production-safe error logging
|
|
18
|
+
|
|
19
|
+
#### Security
|
|
20
|
+
- ✅ Zero vulnerabilities (npm audit clean)
|
|
21
|
+
- ✅ Environment-aware error messages (stack traces hidden in production)
|
|
22
|
+
- ✅ URL encoding for API parameters to prevent injection
|
|
23
|
+
- ✅ Input validation for all parameters
|
|
24
|
+
- ✅ No hardcoded secrets
|
|
25
|
+
|
|
26
|
+
#### Testing
|
|
27
|
+
- ✅ 14 comprehensive tests covering:
|
|
28
|
+
- Plugin registration and configuration
|
|
29
|
+
- Input validation (zip code formats)
|
|
30
|
+
- Error handling (API errors, empty results)
|
|
31
|
+
- Response structure validation
|
|
32
|
+
- Edge cases (null values, whitespace trimming)
|
|
33
|
+
- API mocking for unit testing
|
|
34
|
+
- All tests passing (100%)
|
|
35
|
+
|
|
36
|
+
#### Documentation
|
|
37
|
+
- ✅ README.md with quick start and usage examples
|
|
38
|
+
- ✅ QUICK_START.md for getting started
|
|
39
|
+
- ✅ JSDoc comments in source code
|
|
40
|
+
- ✅ This CHANGELOG
|
|
41
|
+
|
|
42
|
+
#### Breaking Changes
|
|
43
|
+
None - this is the initial release.
|
|
44
|
+
|
|
45
|
+
### Configuration
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
fastify.register(xGeocode, {
|
|
49
|
+
// Required: Geocodio API key
|
|
50
|
+
apiKey: process.env.GEOCODIO_API_KEY,
|
|
51
|
+
|
|
52
|
+
// Optional: Enable/disable plugin (default: true)
|
|
53
|
+
active: true
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### API Methods
|
|
58
|
+
|
|
59
|
+
#### `fastify.geocode.getLatLongByZip(zipCode)`
|
|
60
|
+
|
|
61
|
+
Gets geographic coordinates and address components for a zip code.
|
|
62
|
+
|
|
63
|
+
**Parameters:**
|
|
64
|
+
- `zipCode` (string) - The zip code to geocode
|
|
65
|
+
- Accepts 5-digit format: "10001"
|
|
66
|
+
- Accepts ZIP+4 format: "10001-1234"
|
|
67
|
+
|
|
68
|
+
**Returns:**
|
|
69
|
+
- Promise resolving to an object with:
|
|
70
|
+
- `zip` - Input zip code (trimmed)
|
|
71
|
+
- `lat` - Latitude
|
|
72
|
+
- `lng` - Longitude
|
|
73
|
+
- `city` - City name
|
|
74
|
+
- `county` - County name
|
|
75
|
+
- `state` - State code
|
|
76
|
+
- `country` - Country code
|
|
77
|
+
- `addressComponents` - Full address component object
|
|
78
|
+
|
|
79
|
+
**Throws:**
|
|
80
|
+
- Error if zip code format is invalid
|
|
81
|
+
- Error if API call fails
|
|
82
|
+
- Error if no results found
|
|
83
|
+
|
|
84
|
+
### Validation
|
|
85
|
+
|
|
86
|
+
- Zip codes must be 5 digits or 9 digits (ZIP+4)
|
|
87
|
+
- Invalid formats will throw with descriptive error messages
|
|
88
|
+
- Whitespace is automatically trimmed
|
|
89
|
+
- Null/undefined values are rejected
|
|
90
|
+
|
|
91
|
+
### Error Handling
|
|
92
|
+
|
|
93
|
+
**Development Mode (`NODE_ENV !== 'production'):**
|
|
94
|
+
- Detailed error messages logged to console
|
|
95
|
+
- API status codes and error details included in error messages
|
|
96
|
+
|
|
97
|
+
**Production Mode (`NODE_ENV === 'production'):**
|
|
98
|
+
- Generic error messages returned to clients
|
|
99
|
+
- Sensitive information hidden (API status codes, etc.)
|
|
100
|
+
- Error details logged internally only
|
|
101
|
+
|
|
102
|
+
### Example Usage
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
import Fastify from 'fastify';
|
|
106
|
+
import xGeocode from '@xenterprises/fastify-xgeocode';
|
|
107
|
+
|
|
108
|
+
const fastify = Fastify();
|
|
109
|
+
|
|
110
|
+
await fastify.register(xGeocode, {
|
|
111
|
+
apiKey: process.env.GEOCODIO_API_KEY
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
fastify.get('/location/:zip', async (request, reply) => {
|
|
115
|
+
try {
|
|
116
|
+
const location = await fastify.geocode.getLatLongByZip(request.params.zip);
|
|
117
|
+
return { success: true, data: location };
|
|
118
|
+
} catch (error) {
|
|
119
|
+
reply.status(400);
|
|
120
|
+
return { success: false, error: error.message };
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
await fastify.listen({ port: 3000 });
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Dependencies
|
|
128
|
+
- `fastify-plugin` - ^5.0.0
|
|
129
|
+
- `fastify` (peer) - ^5.0.0
|
|
130
|
+
|
|
131
|
+
### Known Limitations
|
|
132
|
+
- Requires valid Geocodio API key
|
|
133
|
+
- API rate limits apply based on your Geocodio account
|
|
134
|
+
- Reverse geocoding (coordinates to address) not yet implemented
|
|
135
|
+
|
|
136
|
+
### Future Enhancements
|
|
137
|
+
- [ ] Reverse geocoding support
|
|
138
|
+
- [ ] Caching for frequently geocoded zip codes
|
|
139
|
+
- [ ] Batch geocoding support
|
|
140
|
+
- [ ] Support for address-based geocoding
|
|
141
|
+
|
|
142
|
+
### License
|
|
143
|
+
|
|
144
|
+
ISC
|
package/QUICK_START.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# xGeocode Quick Start
|
|
2
|
+
|
|
3
|
+
Get up and running with geocoding in 5 minutes.
|
|
4
|
+
|
|
5
|
+
## 1. Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @xenterprises/fastify-xgeocode
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 2. Get API Key
|
|
12
|
+
|
|
13
|
+
1. Sign up at [geocod.io](https://geocod.io)
|
|
14
|
+
2. Get your free or paid API key from the dashboard
|
|
15
|
+
3. Add to your `.env` file:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
GEOCODIO_API_KEY=your_api_key_here
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 3. Register Plugin
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
import Fastify from 'fastify';
|
|
25
|
+
import xGeocode from '@xenterprises/fastify-xgeocode';
|
|
26
|
+
|
|
27
|
+
const fastify = Fastify();
|
|
28
|
+
|
|
29
|
+
// Register the plugin
|
|
30
|
+
fastify.register(xGeocode, {
|
|
31
|
+
apiKey: process.env.GEOCODIO_API_KEY
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export default fastify;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 4. Use in Routes
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
// Get coordinates from zip code
|
|
41
|
+
fastify.get('/location/:zip', async (request, reply) => {
|
|
42
|
+
const location = await fastify.geocode.getLatLongByZip(request.params.zip);
|
|
43
|
+
return location;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// With error handling
|
|
47
|
+
fastify.get('/geo/:zip', async (request, reply) => {
|
|
48
|
+
try {
|
|
49
|
+
const location = await fastify.geocode.getLatLongByZip(request.params.zip);
|
|
50
|
+
return {
|
|
51
|
+
success: true,
|
|
52
|
+
data: location
|
|
53
|
+
};
|
|
54
|
+
} catch (error) {
|
|
55
|
+
reply.status(400);
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
error: error.message
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 5. Test It
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
curl http://localhost:3000/location/10001
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Expected response:
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"zip": "10001",
|
|
74
|
+
"lat": 40.7506,
|
|
75
|
+
"lng": -73.9972,
|
|
76
|
+
"city": "New York",
|
|
77
|
+
"county": "New York County",
|
|
78
|
+
"state": "NY",
|
|
79
|
+
"country": "US",
|
|
80
|
+
"addressComponents": {
|
|
81
|
+
"number": "",
|
|
82
|
+
"street": "",
|
|
83
|
+
"suffix": "",
|
|
84
|
+
"city": "New York",
|
|
85
|
+
"county": "New York County",
|
|
86
|
+
"state": "NY",
|
|
87
|
+
"zip": "10001",
|
|
88
|
+
"country": "US"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Configuration Options
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
fastify.register(xGeocode, {
|
|
97
|
+
// Required
|
|
98
|
+
apiKey: process.env.GEOCODIO_API_KEY,
|
|
99
|
+
|
|
100
|
+
// Optional - disable the plugin if needed
|
|
101
|
+
active: process.env.ENABLE_GEOCODING !== 'false'
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Error Handling
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
fastify.get('/safe-geo/:zip', async (request, reply) => {
|
|
109
|
+
try {
|
|
110
|
+
const location = await fastify.geocode.getLatLongByZip(request.params.zip);
|
|
111
|
+
return location;
|
|
112
|
+
} catch (error) {
|
|
113
|
+
fastify.log.error(error);
|
|
114
|
+
reply.status(400);
|
|
115
|
+
return { error: 'Failed to geocode address' };
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Next Steps
|
|
121
|
+
|
|
122
|
+
- Check out the [README](./README.md) for more details
|
|
123
|
+
- See [API Reference](./README.md#api-reference) for all available methods
|
|
124
|
+
- Get an API key: https://geocod.io
|
|
125
|
+
|
|
126
|
+
That's it! You're ready to geocode addresses in your Fastify app.
|
package/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# xGeocode
|
|
2
|
+
|
|
3
|
+
A lightweight Fastify plugin for Geocodio API integration. Provides convenient methods for geocoding addresses and retrieving geographic coordinates.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ Easy Geocodio API integration
|
|
8
|
+
- ✅ Get latitude/longitude from zip codes
|
|
9
|
+
- ✅ Retrieve address components (city, county, state, country)
|
|
10
|
+
- ✅ Optional plugin (can be disabled)
|
|
11
|
+
- ✅ Error handling with detailed logging
|
|
12
|
+
- ✅ Fastify 5.x compatible
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @xenterprises/fastify-xgeocode
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
### 1. Register the Plugin
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
import Fastify from 'fastify';
|
|
26
|
+
import xGeocode from '@xenterprises/fastify-xgeocode';
|
|
27
|
+
|
|
28
|
+
const fastify = Fastify();
|
|
29
|
+
|
|
30
|
+
fastify.register(xGeocode, {
|
|
31
|
+
apiKey: process.env.GEOCODIO_API_KEY
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await fastify.listen({ port: 3000 });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Use in Routes
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
fastify.get('/location/:zip', async (request, reply) => {
|
|
41
|
+
const { zip } = request.params;
|
|
42
|
+
const location = await fastify.geocode.getLatLongByZip(zip);
|
|
43
|
+
return location;
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Configuration
|
|
48
|
+
|
|
49
|
+
### Options
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
fastify.register(xGeocode, {
|
|
53
|
+
// Required: Geocodio API key
|
|
54
|
+
apiKey: process.env.GEOCODIO_API_KEY,
|
|
55
|
+
|
|
56
|
+
// Optional: Enable/disable plugin (default: true)
|
|
57
|
+
active: true
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Usage Examples
|
|
62
|
+
|
|
63
|
+
### Get Coordinates from Zip Code
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
const location = await fastify.geocode.getLatLongByZip('10001');
|
|
67
|
+
console.log(location);
|
|
68
|
+
// {
|
|
69
|
+
// zip: '10001',
|
|
70
|
+
// lat: 40.7506,
|
|
71
|
+
// lng: -73.9972,
|
|
72
|
+
// city: 'New York',
|
|
73
|
+
// county: 'New York County',
|
|
74
|
+
// state: 'NY',
|
|
75
|
+
// country: 'US',
|
|
76
|
+
// addressComponents: { ... }
|
|
77
|
+
// }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### In a Route
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
fastify.get('/geo/:zip', async (request, reply) => {
|
|
84
|
+
try {
|
|
85
|
+
const data = await fastify.geocode.getLatLongByZip(request.params.zip);
|
|
86
|
+
return { success: true, data };
|
|
87
|
+
} catch (error) {
|
|
88
|
+
reply.status(400);
|
|
89
|
+
return { success: false, error: error.message };
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Environment Variables
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
GEOCODIO_API_KEY=your_api_key_here
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## API Reference
|
|
101
|
+
|
|
102
|
+
### `fastify.geocode.getLatLongByZip(zipCode)`
|
|
103
|
+
|
|
104
|
+
Gets geographic coordinates and address components for a zip code.
|
|
105
|
+
|
|
106
|
+
**Parameters:**
|
|
107
|
+
- `zipCode` (string) - The zip code to geocode
|
|
108
|
+
|
|
109
|
+
**Returns:**
|
|
110
|
+
- Promise resolving to an object with:
|
|
111
|
+
- `zip` - Input zip code
|
|
112
|
+
- `lat` - Latitude
|
|
113
|
+
- `lng` - Longitude
|
|
114
|
+
- `city` - City name
|
|
115
|
+
- `county` - County name
|
|
116
|
+
- `state` - State code
|
|
117
|
+
- `country` - Country code
|
|
118
|
+
- `addressComponents` - Full address component object
|
|
119
|
+
|
|
120
|
+
**Throws:**
|
|
121
|
+
- Error if no results found
|
|
122
|
+
- Error if API call fails
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
ISC
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xenterprises/fastify-xgeocode",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.1",
|
|
5
|
+
"description": "Fastify plugin for Geocodio API integration with address geocoding and reverse geocoding.",
|
|
6
|
+
"main": "src/xGeocode.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "fastify start -l info server/app.js",
|
|
9
|
+
"dev": "fastify start -w -l info -P server/app.js",
|
|
10
|
+
"test": "node --test test/xGeocode.test.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"fastify",
|
|
14
|
+
"geocoding",
|
|
15
|
+
"geocodio",
|
|
16
|
+
"geolocation",
|
|
17
|
+
"addresses",
|
|
18
|
+
"coordinates"
|
|
19
|
+
],
|
|
20
|
+
"author": "Tim Mushen",
|
|
21
|
+
"license": "ISC",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://gitlab.com/x-enterprises/fastify-plugins/fastify-x-geocode"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://gitlab.com/x-enterprises/fastify-plugins/fastify-x-geocode/-/issues"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://gitlab.com/x-enterprises/fastify-plugins/fastify-x-geocode#readme",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"fastify-plugin": "^5.0.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^22.7.4",
|
|
35
|
+
"fastify": "^5.1.0"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"fastify": "^5.0.0"
|
|
39
|
+
}
|
|
40
|
+
}
|