Class: Clickwrap::IpGeolocation::Resolver
- Inherits:
-
Object
- Object
- Clickwrap::IpGeolocation::Resolver
- Defined in:
- lib/clickwrap/ip_geolocation/resolver.rb
Overview
The adapter contract every IP geolocation resolver implements.
class MyResolver < Clickwrap::IpGeolocation::Resolver
def resolve(ip_address, http_request: nil)
row = MyProvider.lookup(ip_address, http_request:) or
return Location.unavailable(reason: "provider_had_no_row", provider_name: "my_provider")
Location.new(
country_code: row.country_iso,
provider_name: "my_provider",
provider_source: "my_provider_city_database",
database_version: row.database_build,
estimated: true,
resolved_at: Clickwrap.now
)
end
def capabilities = %i[country]
end
Subclassing is optional — Clickwrap.config.ip_geolocation_resolver
accepts anything that responds to #resolve — but inheriting documents
the intent and gives you the contract's own error messages when a method
is missing.
Three obligations that are easy to miss, and that the rest of the gem depends on:
1. Return nil ONLY for a field the provider genuinely did not supply.
Never a placeholder string. "Unknown" written into a country name is
indistinguishable from a country a provider actually reported, and
collapsing those two states is exactly what a receipt must not do.
2. Say who answered. Set `provider_name`, and `provider_source` when the
provider has more than one source (a local city database and an edge
network are not the same evidence). Attach `database_version`,
`database_sha256`, `accuracy_radius_in_kilometers`, and
`accuracy_radius_confidence_percentage` whenever the provider gives
them: the extractor stores that provenance with any coordinate it
keeps, because coordinates without uncertainty overclaim.
3. Never infer trust from a provider's own headers. Leave
`source_was_verified_by_host` false unless the HOST has explicitly
told the adapter that its deployment blocks direct origin access or
sanitizes those headers. A `CF-*` header is a client-supplied string
until the deployment proves otherwise.
A resolver is called SYNCHRONOUSLY, before the evidence and domain
transaction opens, so it must be fast and must not raise for ordinary
conditions. A private, loopback, or reserved address is an ordinary
condition: return Location.unavailable(...), do not raise. Clickwrap
rescues a raising resolver and records the failure rather than losing it,
but a reason string you chose is better evidence than an exception class
Clickwrap had to guess a name from.
Direct Known Subclasses
Instance Method Summary collapse
-
#capabilities ⇒ Object
Which of
Clickwrap::Vocabulary::IP_GEOLOCATION_DATA_FIELDSthis resolver can supply at all, as symbols. -
#resolve(ip_address, http_request: nil) ⇒ Object
Estimate a location for one observed IP address.
Instance Method Details
#capabilities ⇒ Object
Which of Clickwrap::Vocabulary::IP_GEOLOCATION_DATA_FIELDS this
resolver can supply at all, as symbols.
This is a statement about the adapter and its provider, not about any
one lookup: a Cloudflare header set structurally supplies no accuracy
radius, which is a different fact from a MaxMind database that supplies
one but had no value for this address. Clickwrap uses the difference to
explain an empty result honestly, and clickwrap:doctor uses it to tell
a host that a policy authorizes a field its resolver can never fill.
89 90 91 92 93 94 |
# File 'lib/clickwrap/ip_geolocation/resolver.rb', line 89 def capabilities raise NotImplementedError, "#{self.class} must implement #capabilities and return the subset of " \ "Clickwrap::Vocabulary::IP_GEOLOCATION_DATA_FIELDS it can supply, as symbols. " \ "Return [] if it can supply none." end |
#resolve(ip_address, http_request: nil) ⇒ Object
Estimate a location for one observed IP address.
Returns a Location — populated, or Location.unavailable(reason:, provider_name:). Returning nil is permitted for an adapter that has
nothing at all to say; Clickwrap records it as resolver_returned_no_result,
which is a less useful receipt than a reason you wrote yourself.
73 74 75 76 77 78 |
# File 'lib/clickwrap/ip_geolocation/resolver.rb', line 73 def resolve(ip_address, http_request: nil) raise NotImplementedError, "#{self.class} must implement #resolve(ip_address, http_request: nil) and return a " \ "Clickwrap::IpGeolocation::Location (or nil). See the contract in " \ "lib/clickwrap/ip_geolocation/resolver.rb." end |