internetdata

package module
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2026 License: MIT Imports: 13 Imported by: 0

README

InternetData InternetData Go Client Library

Go Reference license

The official Go client library for the InternetData API.

The library downloads the IP and network databases your organization is licensed for, in CSV.GZ or MMDB, and tells you what is inside each one before you fetch it.

Getting Started

go get github.com/internetdata/sdk-go

Requires Go 1.24 or newer. The module path ends in sdk-go, but the package it declares is internetdata:

import internetdata "github.com/internetdata/sdk-go"

Usage

Every database published today is licensed, so start with an API key carrying the db.download scope. Create one in the console and pass it to New as an option:

client, err := internetdata.New(internetdata.WithAPIKey(os.Getenv("INTERNETDATA_API_KEY")))
if err != nil {
    log.Fatal(err)
}

databases, err := client.Database.List(ctx)
for _, db := range databases {
    fmt.Println(db.Base, db.Standing)   // bogon_ip licensed
}

Every call hangs off client.Database, which is the whole of this API and is where the sibling VPNDetection library keeps the same seven calls.

The catalog

List returns one entry per database FAMILY, with your licence beside it. A licence covers the family, while a download names one of its versions, so the ids you pass to everything else come from Versions:

for _, db := range databases {
    if db.Standing != internetdata.StandingLicensed {
        continue
    }
    for _, v := range db.Versions {
        fmt.Println(v.ID, v.Formats)    // vpn_ip_v1 [csvgz mmdb]
    }
}

Standing is licensed, expired or unlicensed, and LicenseType is what your licence permits: evaluation, standard, redistribute, or nil when there is no licence at all. Old versions are frozen rather than migrated, so both stay downloadable.

What is inside one, before you fetch it

Metadata carries the row count, the build date, the columns of each format and the byte size of each file, without downloading anything. Poll it to decide whether today's build is worth fetching, and read Size to budget a transfer before you start one:

meta, err := client.Database.Metadata(ctx, "vpn_ip_v1")
fmt.Println(meta.Updated, meta.Entries, meta.Size["mmdb"])

for _, column := range meta.Schema["csvgz"] {
    fmt.Println(column.Name, column.Type)
}
Downloading

DownloadFile writes one file to a path, streaming it straight to disk so that nothing bigger than a chunk is ever held in memory:

written, err := client.Database.DownloadFile(ctx, "vpn_ip_v1", internetdata.FormatMMDB, "./vpn_ip_v1.mmdb")
fmt.Printf("%d bytes\n", written)

The bytes land in a neighboring .part file that is renamed on completion, so a transfer that dies half way leaves no truncated file that reads as a whole database, and a failed refresh cannot destroy the copy already there.

Or stream it into a writer of your own, or take a small one as bytes:

written, err := client.Database.Download(ctx, "vpn_ip_v1", internetdata.FormatMMDB, w)
raw, err := client.Database.DownloadBytes(ctx, "bogon_ip_v1", internetdata.FormatCSVGZ)

DownloadBytes holds the whole file in memory, and the catalog spans five orders of magnitude, so use DownloadFile for anything you have not measured against Metadata's Size.

Downloading it yourself

The API answers a download with a redirect to a time-limited URL on object storage. DownloadURL hands you that URL rather than following it, so you can pass it to a downloader, a job queue or another machine:

url, err := client.Database.DownloadURL(ctx, "vpn_ip_v1", internetdata.FormatMMDB)

The link is presigned and so authorizes itself; it carries no API key of yours, and the library never sends your key to object storage. It authorizes the START of a transfer, so one already running is not interrupted when the link lapses.

Verifying a download

Checksums returns all four digests the exporter publishes for one file:

sums, err := client.Database.Checksums(ctx, "vpn_ip_v1", internetdata.FormatMMDB)
fmt.Println(sums.SHA256)
Download history

Downloads is your organization's recent attempts, newest first, refusals included: a denial is what answers "it stopped working", and its absence answers nothing.

history, err := client.Database.Downloads(ctx, 50)
for _, attempt := range history {
    fmt.Println(attempt.Created, attempt.DatasetID, attempt.Outcome)
}
Errors

Failures return an *internetdata.Error carrying a Kind, the API's own result code, and a Retryable flag:

_, err := client.Database.DownloadURL(ctx, "vpn_ip_v1", internetdata.FormatMMDB)
var apiErr *internetdata.Error
if errors.As(err, &apiErr) {
    fmt.Println(apiErr.Kind, apiErr.Message, apiErr.Retryable())
}

Kind is one of bad_request, unauthorized, forbidden, rate_limited, quota_exceeded, server_error or network. Message is the API's rc, which is what separates two refusals that share a status: NOT_LICENSED means buy it and LICENSE_EXPIRED means renew it, and both are 403.

Note that rate_limited and quota_exceeded both arrive as HTTP 429 and are not the same thing. A rate limit is when the API faces extreme traffic bursts and so retrying later works; but a spent quota needs your allowance raised or the window to roll over. The library retries rate limits for you, but not if your quota is exceeded.

Your catalog is yours

Other Libraries

There are official InternetData client libraries available for many languages including PHP, Python, Go, Java, Ruby, and many popular frameworks such as Django, Rails, and Laravel. See our GitHub at https://github.com/internetdata for more.

About InternetData

IP, ASN and Domain data to reveal unique insights about the internet. APIs, Databases and Live Feeds available.

InternetData

License

This project is licensed under the MIT License.

Documentation

Overview

Package internetdata is the official Go client library for the InternetData API: licensed IP and network datasets, downloaded as CSV.GZ or MMDB.

Start with New and Client.Database.List. Every database published today is licensed, so pass WithAPIKey a key carrying the db.download scope; the option is optional because what this API serves without one is a product decision rather than the client's to refuse.

Index

Constants

View Source
const (
	StandingLicensed   = api.DatabaseStandingLicensed
	StandingExpired    = api.DatabaseStandingExpired
	StandingUnlicensed = api.DatabaseStandingUnlicensed
)

Standing tells you whether a database is yours today. It never says a database does not exist: a family built for one customer is simply absent from another organization's listing.

View Source
const (
	LicenseTypeEvaluation   = api.Evaluation
	LicenseTypeStandard     = api.Standard
	LicenseTypeRedistribute = api.Redistribute
)

LicenseType is nil rather than one of these when there is no licence at all, so read the pointer before comparing it.

View Source
const (
	DownloadOutcomeOK           = api.DownloadOutcomeOk
	DownloadOutcomeUnauthorized = api.DownloadOutcomeUnauthorized
	DownloadOutcomeDenied       = api.DownloadOutcomeDenied
	DownloadOutcomeExpired      = api.DownloadOutcomeExpired
	DownloadOutcomeUnknown      = api.DownloadOutcomeUnknown
	DownloadOutcomeUnavailable  = api.DownloadOutcomeUnavailable
)
View Source
const DefaultBaseURL = "https://internetdata.io"

DefaultBaseURL is the production API. Override it with WithBaseURL.

Variables

This section is empty.

Functions

This section is empty.

Types

type Checksums

type Checksums struct {
	MD5    string `json:"md5"`
	SHA1   string `json:"sha1"`
	SHA256 string `json:"sha256"`
	SHA512 string `json:"sha512"`
}

Checksums are the digests of one published file.

Spelled out rather than aliased to the generated struct, whose Md5 and Sha256 are not the names a Go caller expects, and which every other InternetData and VPNDetection SDK writes the same way.

type Client

type Client struct {
	// Database is the licensed database catalog and its downloads. Every call
	// hangs off it rather than off the client, which is how the VPNDetection
	// SDKs read too, so one program holding both clients spells the two the
	// same way.
	Database *DatabaseAPI
}

Client is a client for the InternetData API. It is safe for concurrent use.

Nothing it answers is cached. What your organization may see depends on the key, so a listing held from one client is not an answer for another, and a catalog is small enough that re-reading it costs less than being wrong about whose it was.

func New

func New(opts ...Option) (*Client, error)

New builds a client. Without WithAPIKey it sends no Authorization header at all, which every endpoint published today answers 401.

type Database

type Database = api.Database

Database is one database FAMILY, with your organization's licence beside it. LicenseType, Starts and Expires are nil when there is no licence.

type DatabaseAPI

type DatabaseAPI struct {
	// contains filtered or unexported fields
}

DatabaseAPI is the licensed database catalog and its downloads, reached through Client.Database.

Spelled DatabaseAPI rather than Database because Database is already this API's own shape for one database family, and it is what the other InternetData SDKs call this type.

func (*DatabaseAPI) Checksums

func (d *DatabaseAPI) Checksums(ctx context.Context, id string, format Format) (*Checksums, error)

Checksums are the digests of one published file, for verifying a download. All four the exporter writes are returned, because which of them a caller wants is not this library's decision.

func (*DatabaseAPI) Download

func (d *DatabaseAPI) Download(
	ctx context.Context, id string, format Format, dst io.Writer,
) (int64, error)

Download streams one database file into dst and returns the bytes written.

Nothing beyond a single chunk is ever held in memory, whatever the file weighs. The transfer takes its deadline from ctx rather than from the HTTP client's Timeout, which would cap the whole body: 30 seconds is a sane bound on a catalog read and the wrong one on a gigabyte.

A failure DURING the transfer is returned as it happened rather than wrapped in an *Error: a reset socket and a full disk are different problems, and only one of them is ours.

func (*DatabaseAPI) DownloadBytes

func (d *DatabaseAPI) DownloadBytes(ctx context.Context, id string, format Format) ([]byte, error)

DownloadBytes downloads one database file and hands back its bytes.

This holds the ENTIRE file in memory, and the catalog spans five orders of magnitude, from bogon_asn_v1 at a few hundred bytes to the largest IP feeds at several gigabytes. Metadata publishes a Size per format; read it first, or use Download or DownloadFile for anything you have not measured.

func (*DatabaseAPI) DownloadFile

func (d *DatabaseAPI) DownloadFile(
	ctx context.Context, id string, format Format, path string,
) (int64, error)

DownloadFile writes one database file to path and returns the bytes written.

The bytes land in a neighboring .part file that is renamed on completion, so a transfer that dies half way leaves no truncated file that reads as a whole database, and a failed refresh cannot destroy the copy already there. Otherwise identical to Download.

func (*DatabaseAPI) DownloadURL

func (d *DatabaseAPI) DownloadURL(ctx context.Context, id string, format Format) (string, error)

DownloadURL is the time-limited URL for one database file.

The API answers 302 to object storage and the redirect is NOT followed: the URL is returned so a caller can decide how to transfer a file that runs to gigabytes, hand it to a downloader, or pass it on without passing on the API key. The link is presigned and so authorizes itself; it authorizes the START of a transfer, so one already running is not interrupted when it lapses.

func (*DatabaseAPI) Downloads

func (d *DatabaseAPI) Downloads(ctx context.Context, limit int) ([]DownloadAttempt, error)

Downloads is your organization's recent download attempts, newest first. A limit of zero or less takes the API's own default of 50, and it is clamped to 200.

Refusals are listed too: a denial is what answers "it stopped working", and its absence answers nothing.

func (*DatabaseAPI) List

func (d *DatabaseAPI) List(ctx context.Context) ([]Database, error)

List is the published catalog, with your organization's licence beside each family. A licence covers a family, while a download names one of its versions, so the ids the download and checksum calls take come from Database.Versions.

The listing is the SERVER's answer about YOUR key and nothing else assembles it. A database commissioned for a single customer is absent for every other organization rather than listed as unlicensed, so what you get back is not necessarily what another key gets back, and neither the whole catalog nor any part of it can be reconstructed from another source.

func (*DatabaseAPI) Metadata

func (d *DatabaseAPI) Metadata(ctx context.Context, id string) (*DatabaseMetadata, error)

Metadata is what is inside one database: its columns per format, sample rows, the row count and the byte size of each file. It carries Updated and Entries without downloading anything, so poll it to decide whether today's build is worth fetching, and read Size to budget a transfer before starting one.

One document describes every format the database is built in, which is why there is no format argument.

type DatabaseMetadata

type DatabaseMetadata = api.DatabaseMetadata

DatabaseMetadata is the build document the exporter writes, served through unchanged.

type DatabaseMetadataColumn

type DatabaseMetadataColumn = api.DatabaseMetadataColumn

DatabaseMetadataColumn is one column of one format's schema.

type DatabaseVersion

type DatabaseVersion = api.DatabaseVersion

DatabaseVersion is one published version of a family. Its ID is what the download, checksum and metadata calls take. Old versions are frozen rather than migrated, so both stay downloadable.

type Date

type Date = types.Date

Date is a calendar date with no time of day, as DatabaseMetadata.Updated carries.

type DownloadAttempt

type DownloadAttempt = api.Download

DownloadAttempt is one entry of the download history, refusals included. Bytes is the object size at redirect time rather than bytes delivered: the transfer runs straight from object storage, so how much of it was taken is not observed.

type DownloadOutcome

type DownloadOutcome = api.DownloadOutcome

DownloadOutcome is how one download attempt ended.

type Error

type Error struct {
	Kind ErrorKind
	// Message is the API's own result code, or a transport failure's text. The
	// codes are deliberately not an enum on the wire, so one added later stays
	// readable to a client built today.
	Message string
	// StatusCode is the HTTP status, or 0 when no response was received.
	StatusCode int
	// RetryAfter is how long the server asked us to wait. Zero when it did not
	// ask, which on a 429 means an allowance is spent rather than throttled.
	RetryAfter time.Duration
	// contains filtered or unexported fields
}

Error is what every failure from this package unwraps to. Recover it with errors.As and branch on Kind.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Retryable

func (e *Error) Retryable() bool

Retryable reports whether retrying this exact request could succeed.

func (*Error) Unwrap

func (e *Error) Unwrap() error

type ErrorKind

type ErrorKind string

ErrorKind says why a request failed.

KindRateLimited and KindQuotaExceeded both arrive as HTTP 429 and are NOT the same thing. A rate limit is the API protecting itself, carries Retry-After, and retrying works. A spent quota carries no such header and retrying will not help until the window rolls over or the limit is raised. The header is the only thing that distinguishes them.

const (
	KindBadRequest    ErrorKind = "bad_request"
	KindUnauthorized  ErrorKind = "unauthorized"
	KindForbidden     ErrorKind = "forbidden"
	KindRateLimited   ErrorKind = "rate_limited"
	KindQuotaExceeded ErrorKind = "quota_exceeded"
	KindServerError   ErrorKind = "server_error"
	KindNetwork       ErrorKind = "network"
)

type Format

type Format string

Format is a format a database is published in. Not every one is built in every format: the _provider catalogs are keyed by provider id rather than by IP range, so no MMDB exists for them, and asking for one is an error rather than an empty answer. DatabaseVersion.Formats says which exist.

const (
	FormatCSVGZ Format = "csvgz"
	FormatMMDB  Format = "mmdb"
)

type LicenseType added in v1.1.0

type LicenseType = api.DatabaseLicenseType

LicenseType is what a licence permits you to do with the data.

type Option

type Option func(*config) error

Option configures a Client.

func WithAPIKey

func WithAPIKey(key string) Option

WithAPIKey authenticates as the key's organization, which is what decides which databases are listed at all and which of them may be downloaded.

The key comes from the console and needs the db.download scope. Keys are default-deny, so an existing key does not reach these endpoints until the scope is added to it.

func WithBaseURL

func WithBaseURL(rawURL string) Option

WithBaseURL points the client at a different deployment of the API.

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient supplies the HTTP client to send with, for a custom transport, proxy or timeout. Without it the SDK uses a client with a 30 second timeout.

The client is copied rather than mutated, and the copy adds a CheckRedirect that defers to yours (see DatabaseAPI.DownloadURL). A dataset transfer runs on a second copy with Timeout cleared, and is bounded by its context instead.

func WithRetries

func WithRetries(n int) Option

WithRetries sets how many further attempts a transient failure gets. Default 2.

type Standing

type Standing = api.DatabaseStanding

Standing is where a licence stands: live, lapsed, or never bought.

Directories

Path Synopsis
internal
api
Package api provides primitives to interact with the openapi HTTP API.
Package api provides primitives to interact with the openapi HTTP API.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL