Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Ordnance Survey Places API #1678

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
11 changes: 11 additions & 0 deletions README_API_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,17 @@ Regional Street Address Lookups
* **Terms of Service**: https://developer.ordnancesurvey.co.uk/os-api-framework-agreement
* **Limitations**: Only searches postcodes and placenames in England, Wales and Scotland

### Ordnance Survey Places API (`:uk_ordnance_survey_places`)

* **API key**: required (sign up at https://osdatahub.os.uk)
* **Quota**: 0.01 GBP / transaction (600 transactions-per-minute throttle)
* **Region**: England, Wales, Scotland, Northern Ireland, Channel Islands and Isle of Man
* **SSL support**: yes
* **Languages**: English
* **Documentation**: https://osdatahub.os.uk/docs/places/technicalSpecification
* **Terms of Service**: https://www.ordnancesurvey.co.uk/legal
* **Limitations**: Only searches in England, Wales, Scotland, Northern Ireland, Channel Islands and Isle of Man

### PostcodeAnywhere UK (`:postcode_anywhere_uk`)

* **API key**: required
Expand Down
1 change: 1 addition & 0 deletions lib/geocoder/lookup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def street_services
:mapbox,
:mapquest,
:uk_ordnance_survey_names,
:uk_ordnance_survey_places,
:opencagedata,
:pelias,
:pdok_nl,
Expand Down
45 changes: 45 additions & 0 deletions lib/geocoder/lookups/uk_ordnance_survey_places.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require 'geocoder/lookups/base'
require 'geocoder/results/uk_ordnance_survey_places'

module Geocoder::Lookup
class UkOrdnanceSurveyPlaces < Base

def name
'Ordance Survey Places'
end

def supported_protocols
[:https]
end

def base_query_url(query)
"#{protocol}://api.os.uk/search/places/v1/find?"
end

def required_api_key_parts
["key"]
end

def query_url(query)
base_query_url(query) + url_query_string(query)
end

private # -------------------------------------------------------------

def results(query)
return [] unless doc = fetch_data(query)
return [] if doc['header']['totalresults'].zero?
doc['results'].map { |r| r.dig('DPA') || r.dig('LPI') }
end

def query_url_params(query)
{
query: query.sanitized_text,
key: configuration.api_key,
dataset: 'DPA,LPI',
output_srs: 'EPSG:4326',
maxresults: 10
}.merge(super)
end
end
end
56 changes: 56 additions & 0 deletions lib/geocoder/results/uk_ordnance_survey_places.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
require 'geocoder/results/base'
require 'easting_northing'

module Geocoder::Result
class UkOrdnanceSurveyPlaces < Base

def coordinates
@coordinates ||= Geocoder::EastingNorthing.new(
easting: data['X_COORDINATE'],
northing: data['Y_COORDINATE'],
).lat_lng
end

def city
data['POST_TOWN']
end

def county
data['DEPENDENT_LOCALITY']
end
alias state county

def county_code
''
end
alias state_code county_code

def province
{
'E' => 'England',
'W' => 'Wales',
'S' => 'Scotland',
'N' => 'Northern Ireland',
'L' => 'Channel Islands',
'M' => 'Isle of Man',
'J' => ''
}[data['COUNTRY_CODE']]
end

def province_code
data['COUNTRY_CODE']
end

def postal_code
data['POSTCODE']
end

def country
'United Kingdom'
end

def country_code
'UK'
end
end
end
55 changes: 55 additions & 0 deletions test/fixtures/uk_ordnance_survey_places_london
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"header": {
"uri": "https://api.os.uk/search/places/v1/find?query=London&dataset=DPA%2CLPI&output_srs=EPSG%3A4326&maxresults=1",
"query": "query=London",
"offset": 0,
"totalresults": 5734503,
"format": "JSON",
"dataset": "DPA,LPI",
"lr": "EN,CY",
"maxresults": 1,
"matchprecision": 1,
"epoch": "115",
"lastupdate": "2025-01-27",
"output_srs": "EPSG:4326"
},
"results": [
{
"DPA": {
"UPRN": "10009169128",
"UDPRN": "21361575",
"ADDRESS": "LONDON HOUSE, PENCADER, SA39 9AA",
"BUILDING_NAME": "LONDON HOUSE",
"POST_TOWN": "PENCADER",
"POSTCODE": "SA39 9AA",
"RPC": "1",
"X_COORDINATE": 244622.42,
"Y_COORDINATE": 236290.46,
"LNG": -4.2649815,
"LAT": 52.003258,
"STATUS": "APPROVED",
"LOGICAL_STATUS_CODE": "1",
"CLASSIFICATION_CODE": "RD04",
"CLASSIFICATION_CODE_DESCRIPTION": "Terraced",
"LOCAL_CUSTODIAN_CODE": 6825,
"LOCAL_CUSTODIAN_CODE_DESCRIPTION": "CARMARTHENSHIRE",
"COUNTRY_CODE": "W",
"COUNTRY_CODE_DESCRIPTION": "This record is within Wales",
"POSTAL_ADDRESS_CODE": "D",
"POSTAL_ADDRESS_CODE_DESCRIPTION": "A record which is linked to PAF",
"BLPU_STATE_CODE": "2",
"BLPU_STATE_CODE_DESCRIPTION": "In use",
"TOPOGRAPHY_LAYER_TOID": "osgb1000020500141",
"WARD_CODE": "W05001207",
"PARISH_CODE": "W04000523",
"LAST_UPDATE_DATE": "25/03/2022",
"ENTRY_DATE": "24/06/2004",
"BLPU_STATE_DATE": "24/06/2004",
"LANGUAGE": "CY",
"MATCH": 0.3,
"MATCH_DESCRIPTION": "NO MATCH",
"DELIVERY_POINT_SUFFIX": "2A"
}
}
]
}
55 changes: 55 additions & 0 deletions test/fixtures/uk_ordnance_survey_places_sw152qh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"header": {
"uri": "https://api.os.uk/search/places/v1/find?query=London%2C%20SW15%202QH&dataset=DPA%2CLPI&output_srs=EPSG%3A4326&maxresults=1",
"query": "query=London, SW15 2QH",
"offset": 0,
"totalresults": 5656265,
"format": "JSON",
"dataset": "DPA,LPI",
"lr": "EN,CY",
"maxresults": 1,
"matchprecision": 1,
"epoch": "115",
"lastupdate": "2025-01-27",
"output_srs": "EPSG:4326"
},
"results": [
{
"DPA": {
"UPRN": "100022713096",
"UDPRN": "23996615",
"ADDRESS": "2, WESTROW, LONDON, SW15 6RH",
"BUILDING_NUMBER": "2",
"THOROUGHFARE_NAME": "WESTROW",
"POST_TOWN": "LONDON",
"POSTCODE": "SW15 6RH",
"RPC": "2",
"X_COORDINATE": 523366.0,
"Y_COORDINATE": 174494.0,
"LNG": -0.2257836,
"LAT": 51.4559931,
"STATUS": "APPROVED",
"LOGICAL_STATUS_CODE": "1",
"CLASSIFICATION_CODE": "RD04",
"CLASSIFICATION_CODE_DESCRIPTION": "Terraced",
"LOCAL_CUSTODIAN_CODE": 5960,
"LOCAL_CUSTODIAN_CODE_DESCRIPTION": "WANDSWORTH",
"COUNTRY_CODE": "E",
"COUNTRY_CODE_DESCRIPTION": "This record is within England",
"POSTAL_ADDRESS_CODE": "D",
"POSTAL_ADDRESS_CODE_DESCRIPTION": "A record which is linked to PAF",
"BLPU_STATE_CODE": "2",
"BLPU_STATE_CODE_DESCRIPTION": "In use",
"TOPOGRAPHY_LAYER_TOID": "osgb1000041399472",
"WARD_CODE": "E05014030",
"LAST_UPDATE_DATE": "25/03/2022",
"ENTRY_DATE": "19/03/2001",
"BLPU_STATE_DATE": "11/03/2002",
"LANGUAGE": "EN",
"MATCH": 0.4,
"MATCH_DESCRIPTION": "NO MATCH",
"DELIVERY_POINT_SUFFIX": "1F"
}
}
]
}
8 changes: 8 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,14 @@ def default_fixture_filename
end
end

require 'geocoder/lookups/uk_ordnance_survey_places'
class Geocoder::Lookup::UkOrdnanceSurveyPlaces
private
def default_fixture_filename
"#{fixture_prefix}_london"
end
end

require 'geocoder/lookups/geoportail_lu'
class GeoportailLu
private
Expand Down
2 changes: 1 addition & 1 deletion test/unit/lookup_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_search_returns_empty_array_when_no_results

def test_query_url_contains_values_in_params_hash
Geocoder::Lookup.all_services_except_test.each do |l|
next if [:freegeoip, :maxmind_local, :telize, :pointpin, :geoip2, :maxmind_geoip2, :mapbox, :ipdata_co, :ipinfo_io, :ipapi_com, :ipregistry, :ipstack, :postcodes_io, :uk_ordnance_survey_names, :amazon_location_service, :ipbase, :ip2location_lite].include? l # does not use query string
next if [:freegeoip, :maxmind_local, :telize, :pointpin, :geoip2, :maxmind_geoip2, :mapbox, :ipdata_co, :ipinfo_io, :ipapi_com, :ipregistry, :ipstack, :postcodes_io, :uk_ordnance_survey_names, :uk_ordnance_survey_places, :amazon_location_service, :ipbase, :ip2location_lite].include? l # does not use query string
set_api_key!(l)
url = Geocoder::Lookup.get(l).query_url(Geocoder::Query.new(
"test", :params => {:one_in_the_hand => "two in the bush"}
Expand Down
17 changes: 17 additions & 0 deletions test/unit/lookups/uk_ordnance_survey_places.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# encoding: utf-8
require 'test_helper'

class UkOrdnanceSurveyPlacesTest < GeocoderTestCase

def setup
super
Geocoder.configure(lookup: :uk_ordnance_survey_places)
set_api_key!(:uk_ordnance_survey_places)
end

def test_result_on_postcode_search
result = Geocoder.search('SW152QH').first
assert_in_delta 51.4559931, result.coordinates[0]
assert_in_delta -0.2257836, result.coordinates[1]
end
end