Skip to content

Commit

Permalink
Merge pull request #1667 from kulkultech/feature/azure-maps
Browse files Browse the repository at this point in the history
Feature/azure maps
  • Loading branch information
alexreisner authored Dec 4, 2024
2 parents e4e2a88 + bee09bf commit c1a19f2
Show file tree
Hide file tree
Showing 10 changed files with 423 additions and 0 deletions.
12 changes: 12 additions & 0 deletions README_API_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ Global Street Address Lookups
```
* Via environment variables and other external methods. See **Setting AWS Credentials** in the [AWS SDK for Ruby Developer Guide](https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/setup-config.html).

### Azure (`:azure`)

* **Key signup**: https://azure.microsoft.com/en-us/products/azure-maps
* **Quota**: 5,000 request/month with free API key, more with paid keys (see https://azure.microsoft.com/en-us/pricing/details/azure-maps)
* **Region**: world
* **SSL support**: yes
* **Languages**: see https://learn.microsoft.com/en-us/azure/azure-maps/supported-languages
* **Documentation**: https://learn.microsoft.com/en-us/azure/azure-maps
* **Terms of Service**: https://azure.microsoft.com/en-us/support/legal
* **Limitations**: Azure Maps doesn't have any maximum daily limits on the number of requests that can be made, however there are limits to the maximum number of queries per second (QPS) (see https://learn.microsoft.com/en-us/azure/azure-maps/azure-maps-qps-rate-limits)
* **Notes**: To use Azure, set `Geocoder.configure(lookup: :azure, api_key: "your_api_key", azure: { limit: your_limit })` limit is optional - limit the maximum number of results returned, default 10.
### Bing (`:bing`)
* **API key**: required (set `Geocoder.configure(lookup: :bing, api_key: key)`)
Expand Down
1 change: 1 addition & 0 deletions lib/geocoder/lookup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def all_services_with_http_requests
def street_services
@street_services ||= [
:location_iq,
:azure,
:esri,
:google,
:google_premier,
Expand Down
56 changes: 56 additions & 0 deletions lib/geocoder/lookups/azure.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
require 'geocoder/lookups/base'
require 'geocoder/results/azure'

module Geocoder::Lookup
class Azure < Base
def name
'Azure'
end

def required_api_key_parts
['api_key']
end

def supported_protocols
[:https]
end

private

def base_query_url(query)
host = 'atlas.microsoft.com/search/address'

if query.reverse_geocode?
"#{protocol}://#{host}/reverse/json?"
else
"#{protocol}://#{host}/json?"
end
end

def query_url_params(query)
params = {
'api-version' => 1.0,
'language' => query.options[:language] || 'en',
'limit' => configuration[:limit] || 10,
'query' => query.sanitized_text,
'subscription-key' => configuration.api_key
}

params.merge(super)
end

def results(query)
return [] unless (doc = fetch_data(query))

return doc if doc['error']

if doc['results']&.any?
doc['results']
elsif doc['addresses']&.any?
doc['addresses']
else
[]
end
end
end
end
65 changes: 65 additions & 0 deletions lib/geocoder/results/azure.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
require 'geocoder/results/base'

module Geocoder::Result
class Azure < Base
def address
@data['address']['freeformAddress']
end

def building_number
@data['address']['buildingNumber']
end

def city
@data['address']['municipality']
end

def coordinates
if @data['position'].is_a?(String) # reverse geocoding result
@data['position'].split(',').map(&:to_f)
elsif @data['position'].is_a?(Hash) # forward geocoding result
[@data['position']['lat'], @data['position']['lon']]
end
end

def country
@data['address']['country']
end

def country_code
@data['address']['countryCode']
end

def district
@data['address']['municipalitySubdivision']
end

def postal_code
@data['address']['postalCode']
end

def province
@data['address']['countrySubdivision']
end

def state
@data['address']['countrySubdivision']
end

def state_code
@data['address']['countrySubdivisionCode']
end

def street_name
@data['address']['streetName']
end

def street_number
@data['address']['streetNumber']
end

def viewport
@data['viewport'] || {}
end
end
end
8 changes: 8 additions & 0 deletions test/fixtures/azure_invalid_key
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"error": {
"code": "InvalidKey",
"message": "The provided key was incorrect or the account resource does not exist.",
"target": "WWW-Authenticate",
"details": []
}
}
57 changes: 57 additions & 0 deletions test/fixtures/azure_jakarta
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"summary": {
"query": "Jakarta",
"queryType": "NON_NEAR",
"queryTime": 66,
"numResults": 1,
"offset": 0,
"totalResults": 10,
"fuzzyLevel": 1
},
"results": [
{
"type": "Geography",
"id": "6AhgONQ49YLQy9Ku_ocHcA",
"score": 1,
"entityType": "Municipality",
"matchConfidence": {
"score": 1
},
"address": {
"municipality": "Jakarta",
"countrySubdivision": "Jakarta",
"countrySubdivisionName": "Jakarta",
"countrySubdivisionCode": "JK",
"countryCode": "ID",
"country": "Indonesia",
"countryCodeISO3": "IDN",
"freeformAddress": "Jakarta, Jakarta"
},
"position": {
"lat": -6.17476,
"lon": 106.82707
},
"viewport": {
"topLeftPoint": {
"lat": -5.95462, "lon": 106.68588
},
"btmRightPoint": {
"lat": -6.37083, "lon": 106.9729
}
},
"boundingBox": {
"topLeftPoint": {
"lat": -5.95462, "lon": 106.68588
},
"btmRightPoint": {
"lat": -6.37083, "lon": 106.9729
}
},
"dataSources": {
"geometry": {
"id": "00004944-3100-3c00-0000-000023c347ee"
}
}
}
]
}
50 changes: 50 additions & 0 deletions test/fixtures/azure_madison_square_garden
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"summary": {
"query": "madison square garden",
"queryType": "NON_NEAR",
"queryTime": 89,
"numResults": 1,
"offset": 0,
"totalResults": 6,
"fuzzyLevel": 1
},
"results": [
{
"type": "Street",
"id": "QyS-HWGa0fkjABCOcS09Rw",
"score": 0.8939382576343416,
"matchConfidence": {
"score": 0.8939382576343416
},
"address": {
"streetName": "Garten Place",
"municipality": "Madison Heights",
"countrySecondarySubdivision": "Amherst",
"countrySubdivision": "VA",
"countrySubdivisionName": "Virginia",
"countrySubdivisionCode": "VA",
"postalCode": "24572",
"extendedPostalCode": "24572-4418, 24572-4419",
"countryCode": "US",
"country": "United States",
"countryCodeISO3": "USA",
"freeformAddress": "Garten Place, Madison Heights, VA 24572",
"localName": "Madison Heights"
},
"position": {
"lat": 37.484629,
"lon": -79.109597
},
"viewport": {
"topLeftPoint": {
"lat": 37.485,
"lon": -79.11055
},
"btmRightPoint": {
"lat": 37.48439,
"lon": -79.10872
}
}
}
]
}
12 changes: 12 additions & 0 deletions test/fixtures/azure_no_results
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"summary": {
"query": "Jakarta",
"queryType": "NON_NEAR",
"queryTime": 66,
"numResults": 0,
"offset": 0,
"totalResults": 0,
"fuzzyLevel": 1
},
"results": []
}
36 changes: 36 additions & 0 deletions test/fixtures/azure_reverse
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"summary": {
"queryTime": 12,
"numResults": 1
},
"addresses": [
{
"address": {
"buildingNumber": "10",
"streetNumber": "10",
"routeNumbers": [],
"street": "Jalan Mohammad Husni Thamrin",
"streetName": "Jalan Mohammad Husni Thamrin",
"streetNameAndNumber": "Jalan Mohammad Husni Thamrin 10",
"countryCode": "ID",
"countrySubdivision": "DKI Jakarta",
"municipality": "Jakarta",
"postalCode": "10230",
"municipalitySecondarySubdivision": "Menteng",
"country": "Indonesia",
"countryCodeISO3": "IDN",
"freeformAddress": "Jalan Mohammad Husni Thamrin 10, Kecamatan Jakarta, DKI Jakarta 10230",
"boundingBox": {
"northEast": "-6.198818,106.823264",
"southWest": "-6.199555,106.823246",
"entity": "position"
},
"countrySubdivisionName": "DKI Jakarta",
"countrySubdivisionCode": "JK",
"localName": "Jakarta"
},
"position": "-6.199203,106.823082",
"id": "hlyQM4iHOYn16mWumCtnJA"
}
]
}
Loading

0 comments on commit c1a19f2

Please sign in to comment.