Skip to content

Add IPGeolocation.io driver - #413

Open
mateen993 wants to merge 1 commit into
stevebauman:masterfrom
mateen993:add-ipgeolocation-driver
Open

mateen993 wants to merge 1 commit into
stevebauman:masterfrom
mateen993:add-ipgeolocation-driver

Conversation

@mateen993

Copy link
Copy Markdown

Summary

This PR adds a new driver, Stevebauman\Location\Drivers\IpGeolocation, for the IPGeolocation.io IP geolocation API. It follows the same pattern as the existing IpData, IpInfo and Ip2locationio drivers: it extends HttpDriver, builds a URL, and maps the JSON response onto Position.

Nothing existing changes. The driver is opt-in, it is not added to the default driver or fallbacks, and no dependencies are added.

Files changed

File Change
src/Drivers/IpGeolocation.php New driver
tests/Drivers/IpGeolocationTest.php New tests (3)
config/location.php New ipgeolocation.token entry, read from IPGEOLOCATION_TOKEN
readme.md Driver added to the "Available drivers" list

How the driver calls the API

The driver sends one GET request per lookup through the package's existing HTTP client, so the location.http timeout options and HttpDriver::resolveHttpBy() apply as usual:

GET https://api.ipgeolocation.io/v3/ipgeo?apiKey={token}&ip={ip}&fields=location,currency.code,time_zone.name
  • apiKey: the value of location.ipgeolocation.token.
  • ip: the IP being looked up (IPv4 or IPv6). The query string is built with http_build_query(), so IPv6 addresses are encoded correctly.
  • fields: limits the response to the objects the driver maps. It keeps the payload small and doesn't change the price: the base lookup costs 1 credit either way. fields is available on every plan, including the free one.

The driver doesn't use the API's optional paid modules (include=security, abuse and so on), so it works the same on free and paid keys.

Field mapping

Position property API response field Example (8.8.8.8)
countryName location.country_name United States
countryCode location.country_code2 US
regionName location.state_prov California
regionCode location.state_code US-CA
cityName location.city Mountain View
zipCode location.zipcode 94043-1351
postalCode location.zipcode 94043-1351
latitude location.latitude 37.42240
longitude location.longitude -122.08421
timezone time_zone.name America/Los_Angeles
currencyCode currency.code USD

Notes on the mapping:

  • regionCode is passed through exactly as the API returns it, an ISO 3166-2 subdivision code that includes the country prefix (US-CA, SE-AB). Some other drivers return only the subdivision part (CA). I kept the API's value as-is so it isn't lossy, and I'm happy to change it if you prefer the short form for consistency.
  • zipCode and postalCode both get location.zipcode, the same way the IpData driver fills both from one field.
  • latitude and longitude come back from the API as strings, so they are assigned directly to the string-typed Position properties without casting.
  • isoCode, metroCode and areaCode are left null: the API has no matching field.
  • Any field missing from the response is left null (every read uses ?? null).

Error handling

There is no special error handling: the driver relies on HttpDriver::process(). Any non-2xx response makes the driver return false, so the next fallback driver is tried. For this API that covers:

Status When the API returns it
401 Missing or invalid API key, or the subscription can't use the endpoint
404 The IP isn't in the IPGeolocation.io database
423 The IP is private or reserved (bogon), e.g. 10.0.0.1
429 The plan's request limit has been reached

Configuration and usage

  1. Get a free API key at https://app.ipgeolocation.io/login.

  2. Add it to .env:

    IPGEOLOCATION_TOKEN=your-api-key
    
  3. Use the driver as the default or as a fallback in config/location.php:

    use Stevebauman\Location\Drivers\IpGeolocation;
    
    'driver' => IpGeolocation::class,
    
    // or
    'fallbacks' => [
        IpGeolocation::class,
        // ...
    ],

The new config entry follows the existing convention (token, the same key name the ipdata, ipinfo and ip2locationio entries use):

'ipgeolocation' => [
    'token' => env('IPGEOLOCATION_TOKEN'),
],

Tests

tests/Drivers/IpGeolocationTest.php adds 3 tests:

  1. Response mapping: a mocked process() returns a v3 response, and the test asserts the full Position::toArray() output, in the same style as the other driver tests.
  2. Request URL: asserts the exact URL built for an IPv6 address, including the API key and the fields parameter.
  3. Error response: Http::fake() returns HTTP 423 (bogon IP), and the test asserts that Location::get() returns false.

Results:

  • vendor/bin/pest: 38 passed (35 existing + 3 new).
  • pint --test on the changed files: passes.
  • Live check: I also ran the driver against the real API with a free-plan key, looking up 8.8.8.8. It returned the values in the "Example" column of the mapping table above. That check isn't part of the test suite, because it needs a key.

Disclosure

I work at IPGeolocation.io. We will keep this driver in step with the API and respond to issues about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant