Alternative project for ip-geolocation that uses Spring WebFlux instead of Spring MVC.
Table of Contents
Service responsible for fetching the city/state/country of a given IP address. When the IP is absent, the external IP of the machine this service is hosted on will be used instead.
The datasource used at this project is the GeoIP2, provided by MaxMind. It also uses Redis to cache the location associated with the IPs, in order to avoid unnecessary calls to the underlying GeoIP2 data store when the same IP is fetched more than once.
- Java 11+
- Redis running locally on localhost listening to the port 6379 (can be easily run with Docker, check below how to do this).
In order to get started, clone this repository into a directory of choice and run the following commands in it:
# setup redis
docker run --rm -p 6379:6379 --name ip-geolocation-redis -d redis
# compiles the code and generate the executable JAR
./mvnw clean package
# runs the application on port 8080
java -jar target/geolocation-1.0.0.jar
The easiest way of running the application is by using Docker. Inside the project directory, run the following command to spin up the application:
docker-compose up
This application contains both unit and integration tests. In order to run them, execute the following command inside the project directory:
./mvnw clean test
In order to use the application, make sure it's running on port 8080. The root endpoint exposed is geolocation/ips
,
with the following specialized paths:
In order to get the city/state location of an IP address, just call the geolocation/ips/city
endpoint with the ip
query
parameter, like the following:
curl --location --request GET 'http://localhost:8080/geolocation/ips/city?ip=217.138.219.147' \
--header 'Accept: application/json' \
| json_pp
The response:
{
"city": {
"name": "Milan",
"geoNameId": 3173435
},
"state": {
"name": "Milan",
"geoNameId": 3173434,
"isoCode": "MI"
}
}
In case the ip
query parameter is absent, the external IP from the host machine will be used instead:
curl --location --request GET 'http://localhost:8080/geolocation/ips/city' \
--header 'Accept: application/json' \
| json_pp
The response:
{
"city" : {
"name" : "Montreal",
"geoNameId" : 6077243
},
"state" : {
"name" : "Quebec",
"geoNameId" : 6115047,
"isoCode" : "QC"
}
}
In order to get the country of an IP address, just call the geolocation/ips/city
endpoint with the ip
query
parameter, like the following:
curl --location --request GET 'http://localhost:8080/geolocation/ips/country?ip=217.138.219.147' \
--header 'Accept: application/json' \
| json_pp
The response:
{
"country": {
"name": "Italy",
"geoNameId": 3175395,
"isoCode": "IT",
"inEuropeanUnion": true
}
}
In case the ip
query parameter is absent, the external IP from the host machine will be used instead:
curl --location --request GET 'http://localhost:8080/geolocation/ips/country' \
--header 'Accept: application/json' \
| json_pp
The response:
{
"country" : {
"isoCode" : "CA",
"geoNameId" : 6251999,
"inEuropeanUnion" : false,
"name" : "Canada"
}
}
This application follows the basic layered architecture, having the following flow of interactions between them:
controller -> api -> service -> repository
The code is mainly divided in the following packages:
Represents the controller
layer and is the entrypoint of the application. The endpoints and DTOs are declared in this
package. The controller calls are forward to the api
layer for processing.
Represents the api
layer of the application. It contains classes that validate/convert incoming DTOs into domain objects,
and coordinates subsequent calls to services. It should contain as least responsibility as possible, mostly forwarding calls
to another classes/services.
Contains the domain objects that are used in the service
layer of the application. They are immutable.
Represents the service
layer of the application. Most of the application business logic is contained in this package.
It is also responsible for forwarding calls to the repository
layer to fetch the IP address location.
Represents the repository
layer of the application. It contains repository interfaces to get the city/state/country of
an IP address, which uses the GeoIP2 database and Redis for caching.