Unified, free geolocation service built with Java 17 + Spring Boot + Clean Architecture.
GeoLocateAPI provides a simple, reliable and fully free way to obtain geolocation data without relying on commercial APIs or paid subscriptions.
It exposes a clean REST interface for three essential operations:
- IP → Location
- Coordinates → City/Country
- City Name → Coordinates
The service acts as a unified layer over public, open-data providers (ip-api, OpenStreetMap/Nominatim, Open-Meteo), avoiding the friction of API keys, quotas and billing constraints.
The project is intentionally stateless, lightweight and easy to integrate, suitable for backend systems, mobile apps, internal tooling, analytics or prototyping.
- IP → Location lookup
- Coordinates → Reverse geocoding
- City → Coordinates search
- Unified
GeoLocationDatadomain model - Clean Architecture
- Hexagonal provider integration
- Global exception handling
- WireMock integration tests
- MockMvc controller tests
- Auto-generated Swagger/OpenAPI documentation
- Per-endpoint rate limiting (Bucket4j) with standard rate-limit headers
- In-memory response caching (Caffeine) with per-endpoint TTL
- Provider fallback chains for IP lookup and reverse geocoding
- Request validation (IP format, city length, latitude/longitude ranges)
GET /api/v1/geo/ip/{ip}
Example:
curl http://localhost:8080/api/v1/geo/ip/8.8.8.8
GET /api/v1/geo/coordinates?lat=40.0&lon=-8.0
Example:
curl http://localhost:8080/api/v1/geo/coordinates?lat=40.0&lon=-8.0
GET /api/v1/geo/city/{name}
Example:
curl http://localhost:8080/api/v1/geo/city/Lisbon
Each endpoint is protected by per-client rate limits (Bucket4j):
| Tier | Limit | Endpoints |
|---|---|---|
| IP_LOOKUP | 30 req/minute | GET /api/v1/geo/ip/{ip} |
| GEO_SEARCH | 60 req/minute | /coordinates, /city/{name} |
Every response includes:
X-RateLimit-LimitX-RateLimit-Remaining
When the limit is exceeded, the API responds with 429 Too Many Requests,
a Retry-After header (seconds), and:
{ "error": "Too Many Requests", "retryAfter": 12 }Clients are identified by the first X-Forwarded-For entry, falling back to the remote address.
Responses are cached in-memory (Caffeine) to reduce calls to upstream providers:
| Cache | TTL | Max entries |
|---|---|---|
| geo-ip | 24 hours | 500 |
| geo-coordinates | 7 days | 500 |
| geo-city | 7 days | 500 |
Each response includes a cached boolean indicating whether the result came from cache:
{ "ip": "8.8.8.8", "city": "Mountain View", "...": "...", "cached": true }To improve reliability, the API automatically retries with a secondary provider when the primary one is unavailable:
| Operation | Primary | Fallback |
|---|---|---|
| IP → Location | ip-api.com | ipinfo.io |
| Coordinates → City | OSM / Nominatim | BigDataCloud |
| City → Coordinates | Open-Meteo | — (none) |
src/
├─ domain/
├─ application/
├─ infrastructure/
└─ presentation/
Rendered SVG: architecture.svg
Source (PlantUML): architecture.puml
git clone https://github.com/MarkADom/GeoLocateAPI.git
cd GeoLocateAPI
./gradlew bootRun
Once the app is running:
- Swagger UI:
http://localhost:8080/swagger-ui/index.html - OpenAPI JSON:
/v3/api-docs
./gradlew test
- API key authentication
- Test coverage badge
- Dockerfile (optional)
- Persistent caching (Redis) for multi-instance deployments
GeoLocateAPI follows a simple and clean release flow:
- main → stable, production-ready versions
- develop → upcoming improvements and planned features
v1.1.0 — Resilience & Performance Update
Includes:
- GitHub Actions CI pipeline (build + test on PRs)
- Per-endpoint rate limiting (Bucket4j) with rate-limit headers
- Provider fallback chains for IP lookup and reverse geocoding
- In-memory response caching (Caffeine) with per-endpoint TTL
- Request validation (IP format, city length, latitude/longitude ranges)
v1.0.0 — Initial Stable Release
Includes:
- Core geolocation features (IP lookup, reverse geocoding, city search)
- Clean Architecture + Hexagonal structure
- Swagger/OpenAPI documentation
- WireMock + MockMvc test suite
- Architecture diagrams (PlantUML + SVG)
- MIT License
👉 View all releases:
https://github.com/MarkADom/GeoLocateAPI/releases
The core of GeoLocateAPI is complete. Contributions are welcome.
This service was originally built as part of my backend engineering portfolio, focusing on clean architecture, external API integration, structured testing and maintainability.
Developed by Marco Domingues. Focused on clean, testable backend services that are easy to understand, extend and deploy.
This project is distributed under the MIT License.
See the LICENSE file for details.