Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: CI

on:
push:
branches: [master]
pull_request:
branches: [master]

permissions:
contents: read

jobs:
test:
name: Test (Go ${{ matrix.go-version }})
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.21', '1.22', '1.23', '1.24']

steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}

- name: Verify dependencies
run: go mod verify

- name: Vet
run: go vet ./...

- name: Test
run: go test -race -covermode atomic -coverprofile coverage.out ./...

- name: Upload coverage
if: matrix.go-version == '1.24'
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage.out

staticcheck:
name: Static Analysis
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.24'

- name: Install staticcheck
run: go install honnef.co/go/tools/cmd/staticcheck@latest

- name: Run staticcheck
run: staticcheck ./...
17 changes: 0 additions & 17 deletions .travis.yml

This file was deleted.

27 changes: 0 additions & 27 deletions Gopkg.lock

This file was deleted.

29 changes: 0 additions & 29 deletions Gopkg.toml

This file was deleted.

19 changes: 2 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,10 @@
# Use of this source code is governed by the MIT License that can be found in
# the LICENSE file at the root of this repository.

test: vet lint staticcheck tests
test: vet staticcheck tests

prebuild:
go get -u github.com/golang/dep/cmd/dep \
golang.org/x/lint/golint \
honnef.co/go/tools/cmd/staticcheck \
golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow

# this needs to be updated when a future version of 1.13.x includes:
# https://github.com/golang/go/issues/34053
#
# original line now removed:
# go vet -vettool=$(shell which shadow) ./...
vet:
go vet ./...
shadow ./...

lint:
golint -set_exit_status

staticcheck:
staticcheck ./...
Expand All @@ -29,4 +14,4 @@ tests:
go test -race -covermode atomic -cover -coverprofile profile.out ./...
go tool cover -func=profile.out

.PHONY: test prebuild vet lint staticcheck tests
.PHONY: test vet staticcheck tests
185 changes: 144 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,70 +1,173 @@
# ipdata
[![License](https://img.shields.io/github/license/theckman/go-ipdata.svg)](https://github.com/theckman/go-ipdata/blob/master/LICENSE)
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/theckman/go-ipdata)
[![Latest Git Tag](https://img.shields.io/github/tag/theckman/go-ipdata.svg)](https://github.com/theckman/go-ipdata/releases)
[![Travis master Build Status](https://img.shields.io/travis/theckman/go-ipdata/master.svg?label=TravisCI)](https://travis-ci.org/theckman/go-ipdata/branches)
[![Go Cover Test Coverage](https://gocover.io/_badge/github.com/theckman/go-ipdata?v0)](https://gocover.io/github.com/theckman/go-ipdata)
[![Go Report Card](https://goreportcard.com/badge/github.com/theckman/go-ipdata)](https://goreportcard.com/report/github.com/theckman/go-ipdata)
[![CI](https://github.com/ipdata/go/actions/workflows/ci.yml/badge.svg)](https://github.com/ipdata/go/actions/workflows/ci.yml)
[![Go Reference](https://pkg.go.dev/badge/github.com/ipdata/go.svg)](https://pkg.go.dev/github.com/ipdata/go)
[![License](https://img.shields.io/github/license/ipdata/go.svg)](https://github.com/ipdata/go/blob/master/LICENSE)
[![Latest Git Tag](https://img.shields.io/github/tag/ipdata/go.svg)](https://github.com/ipdata/go/releases)
[![Go Report Card](https://goreportcard.com/badge/github.com/ipdata/go)](https://goreportcard.com/report/github.com/ipdata/go)

Package ipdata is a client for the https://ipdata.co API. It provides functions
for looking up data, as well as parsing the data in a programmatic way. The
simplest usage is to build a new client and then use the `Lookup` method.
Package ipdata is a Go client for the [ipdata.co](https://ipdata.co) API. It
provides IP geolocation, threat intelligence, company detection, currency,
timezone, carrier, and language data for any IP address.

## Installation

```
go get github.com/ipdata/go
```

## License
This code is released under the MIT License. Please see the
[LICENSE](https://github.com/theckman/go-ipdata/blob/master/LICENSE) for the
[LICENSE](https://github.com/ipdata/go/blob/master/LICENSE) for the
full content of the license.

## Contributing
If you'd like to contribute to this project, I welcome any pull requests against
this repo. The only ask is that a GitHub issue be opened detailing the desired
functionality before making any pull requests.

## Usage
The service provided by `ipdata` requires an API key before making API calls.
Attempts to create a client without one will fail, as would attempts to contact
the API. You can get an API key from https://ipdata.co/.

Here is a simple example of using the library:
The service provided by ipdata requires an API key. You can get one from
https://ipdata.co/.

### Basic Lookup

```go
package main

```Go
import (
"github.com/ipdata/go"
"fmt"
"fmt"

"github.com/ipdata/go"
)

ipd, _ := ipdata.NewClient("EXAMPLE_API_KEY")
func main() {
client, err := ipdata.NewClient("YOUR_API_KEY")
if err != nil {
panic(err)
}

data, err := client.Lookup("8.8.8.8")
if err != nil {
panic(err)
}

fmt.Printf("IP: %s\n", data.IP)
fmt.Printf("Country: %s (%s)\n", data.CountryName, data.CountryCode)
fmt.Printf("City: %s\n", data.City)
fmt.Printf("ASN: %s (%s)\n", data.ASN.ASN, data.ASN.Name)

if data.Company != nil {
fmt.Printf("Company: %s\n", data.Company.Name)
}

if data.Threat != nil {
fmt.Printf("VPN: %v, Tor: %v, Proxy: %v\n",
data.Threat.IsVPN, data.Threat.IsTOR, data.Threat.IsProxy)
}
}
```

### EU Endpoint (GDPR Compliance)

For GDPR compliance, use `NewEUClient` to route all requests through EU data
centers only (Frankfurt, Paris, and Ireland):

```go
client, err := ipdata.NewEUClient("YOUR_API_KEY")
```

### Field Filtering

Request only specific fields to reduce response size:

data, err := ipd.Lookup("8.8.8.8")
```go
data, err := client.LookupFields("8.8.8.8", []string{"ip", "country_name", "threat"})
if err != nil {
// handle error
panic(err)
}

fmt.Printf("%s (%s)\n", data.IP, data.ASN)
fmt.Printf("%s - %s\n", data.IP, data.CountryName)
```

Errors returned from the lookup function calls may be of type `Error`, which
includes the message from the API and the HTTP status code. The `Error()` method
on this type only returns the message and not the status code. To maintain
compatibility with Go 1.12.x, this is still using github.com/pkg/errors for
error management:
### Bulk Lookup

```Go
Look up multiple IPs in a single request:

```go
results, err := client.BulkLookup([]string{"8.8.8.8", "1.1.1.1"})
if err != nil {
// err may be of type ipdata.Error with index of first failure
// results may still contain partial data
}

for _, ip := range results {
if ip != nil {
fmt.Printf("%s: %s\n", ip.IP, ip.CountryName)
}
}
```

### Error Handling

Errors returned from lookup functions may be of type `Error`, which includes
the message from the API and the HTTP status code:

```go
import "github.com/pkg/errors"

data, err := ipd.Lookup("8.8.8.8")
data, err := client.Lookup("8.8.8.8")
if err != nil {
// do a type assertion on the error
rerr, ok := errors.Cause(err).(ipdata.Error)

if !ok {
// this wasn't a failure from rate limiting
}

fmt.Println("%d: %s", rerr.Code(), rerr.Error())
if apiErr, ok := errors.Cause(err).(ipdata.Error); ok {
fmt.Printf("API error %d: %s\n", apiErr.Code(), apiErr.Error())
}
}
```

## Response Fields

The `IP` struct includes all fields from the ipdata API response:

| Field | Type | Description |
|-------|------|-------------|
| `IP` | `string` | IP address |
| `City` | `string` | City name |
| `Region` | `string` | Region/state name |
| `RegionCode` | `string` | ISO 3166-2 region code |
| `CountryName` | `string` | Country name |
| `CountryCode` | `string` | ISO 3166-1 alpha-2 code |
| `ContinentName` | `string` | Continent name |
| `ContinentCode` | `string` | 2-letter continent code |
| `Latitude` | `float64` | Geographic latitude |
| `Longitude` | `float64` | Geographic longitude |
| `Postal` | `string` | Postal/zip code |
| `CallingCode` | `string` | International calling code |
| `Flag` | `string` | URL to country flag image |
| `EmojiFlag` | `string` | Flag emoji character |
| `EmojiUnicode` | `string` | Unicode representation |
| `IsEU` | `bool` | Whether in the EU |
| `Organization` | `string` | Organization name |
| `ASN` | `ASN` | Autonomous System Number data |
| `Company` | `*Company` | Company/organization data |
| `Carrier` | `*Carrier` | Mobile carrier data |
| `Languages` | `[]Language` | Languages spoken |
| `Currency` | `*Currency` | Local currency info |
| `TimeZone` | `*TimeZone` | Timezone info |
| `Threat` | `*Threat` | Threat intelligence data |
| `Count` | `string` | API request count (24h) |
| `Status` | `int` | HTTP status code |

### Nested Types

**`Company`**: `Name`, `Domain`, `Network`, `Type`

**`ASN`**: `ASN`, `Name`, `Domain`, `Route`, `Type`

**`Carrier`**: `Name`, `MCC`, `MNC`

**`Language`**: `Name`, `Native`, `Code`

**`Currency`**: `Name`, `Code`, `Symbol`, `Native`, `Plural`

**`TimeZone`**: `Name`, `Abbreviation`, `Offset`, `IsDST`, `CurrentTime`

**`Threat`**: `IsTOR`, `IsVPN`, `IsICloudRelay`, `IsProxy`, `IsDatacenter`, `IsAnonymous`, `IsKnownAttacker`, `IsKnownAbuser`, `IsThreat`, `IsBogon`, `Blocklists`, `Scores`

## Contributors

- [Tim Heckman](https://github.com/theckman/) - Created the first version of this library
Loading