Skip to content

Commit c1a19f2

Browse files
authored
Merge pull request #1667 from kulkultech/feature/azure-maps
Feature/azure maps
2 parents e4e2a88 + bee09bf commit c1a19f2

10 files changed

+423
-0
lines changed

README_API_GUIDE.md

+12
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@ Global Street Address Lookups
6161
```
6262
* 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).
6363

64+
### Azure (`:azure`)
65+
66+
* **Key signup**: https://azure.microsoft.com/en-us/products/azure-maps
67+
* **Quota**: 5,000 request/month with free API key, more with paid keys (see https://azure.microsoft.com/en-us/pricing/details/azure-maps)
68+
* **Region**: world
69+
* **SSL support**: yes
70+
* **Languages**: see https://learn.microsoft.com/en-us/azure/azure-maps/supported-languages
71+
* **Documentation**: https://learn.microsoft.com/en-us/azure/azure-maps
72+
* **Terms of Service**: https://azure.microsoft.com/en-us/support/legal
73+
* **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)
74+
* **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.
75+
6476
### Bing (`:bing`)
6577
6678
* **API key**: required (set `Geocoder.configure(lookup: :bing, api_key: key)`)

lib/geocoder/lookup.rb

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def all_services_with_http_requests
3232
def street_services
3333
@street_services ||= [
3434
:location_iq,
35+
:azure,
3536
:esri,
3637
:google,
3738
:google_premier,

lib/geocoder/lookups/azure.rb

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
require 'geocoder/lookups/base'
2+
require 'geocoder/results/azure'
3+
4+
module Geocoder::Lookup
5+
class Azure < Base
6+
def name
7+
'Azure'
8+
end
9+
10+
def required_api_key_parts
11+
['api_key']
12+
end
13+
14+
def supported_protocols
15+
[:https]
16+
end
17+
18+
private
19+
20+
def base_query_url(query)
21+
host = 'atlas.microsoft.com/search/address'
22+
23+
if query.reverse_geocode?
24+
"#{protocol}://#{host}/reverse/json?"
25+
else
26+
"#{protocol}://#{host}/json?"
27+
end
28+
end
29+
30+
def query_url_params(query)
31+
params = {
32+
'api-version' => 1.0,
33+
'language' => query.options[:language] || 'en',
34+
'limit' => configuration[:limit] || 10,
35+
'query' => query.sanitized_text,
36+
'subscription-key' => configuration.api_key
37+
}
38+
39+
params.merge(super)
40+
end
41+
42+
def results(query)
43+
return [] unless (doc = fetch_data(query))
44+
45+
return doc if doc['error']
46+
47+
if doc['results']&.any?
48+
doc['results']
49+
elsif doc['addresses']&.any?
50+
doc['addresses']
51+
else
52+
[]
53+
end
54+
end
55+
end
56+
end

lib/geocoder/results/azure.rb

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require 'geocoder/results/base'
2+
3+
module Geocoder::Result
4+
class Azure < Base
5+
def address
6+
@data['address']['freeformAddress']
7+
end
8+
9+
def building_number
10+
@data['address']['buildingNumber']
11+
end
12+
13+
def city
14+
@data['address']['municipality']
15+
end
16+
17+
def coordinates
18+
if @data['position'].is_a?(String) # reverse geocoding result
19+
@data['position'].split(',').map(&:to_f)
20+
elsif @data['position'].is_a?(Hash) # forward geocoding result
21+
[@data['position']['lat'], @data['position']['lon']]
22+
end
23+
end
24+
25+
def country
26+
@data['address']['country']
27+
end
28+
29+
def country_code
30+
@data['address']['countryCode']
31+
end
32+
33+
def district
34+
@data['address']['municipalitySubdivision']
35+
end
36+
37+
def postal_code
38+
@data['address']['postalCode']
39+
end
40+
41+
def province
42+
@data['address']['countrySubdivision']
43+
end
44+
45+
def state
46+
@data['address']['countrySubdivision']
47+
end
48+
49+
def state_code
50+
@data['address']['countrySubdivisionCode']
51+
end
52+
53+
def street_name
54+
@data['address']['streetName']
55+
end
56+
57+
def street_number
58+
@data['address']['streetNumber']
59+
end
60+
61+
def viewport
62+
@data['viewport'] || {}
63+
end
64+
end
65+
end

test/fixtures/azure_invalid_key

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"error": {
3+
"code": "InvalidKey",
4+
"message": "The provided key was incorrect or the account resource does not exist.",
5+
"target": "WWW-Authenticate",
6+
"details": []
7+
}
8+
}

test/fixtures/azure_jakarta

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"summary": {
3+
"query": "Jakarta",
4+
"queryType": "NON_NEAR",
5+
"queryTime": 66,
6+
"numResults": 1,
7+
"offset": 0,
8+
"totalResults": 10,
9+
"fuzzyLevel": 1
10+
},
11+
"results": [
12+
{
13+
"type": "Geography",
14+
"id": "6AhgONQ49YLQy9Ku_ocHcA",
15+
"score": 1,
16+
"entityType": "Municipality",
17+
"matchConfidence": {
18+
"score": 1
19+
},
20+
"address": {
21+
"municipality": "Jakarta",
22+
"countrySubdivision": "Jakarta",
23+
"countrySubdivisionName": "Jakarta",
24+
"countrySubdivisionCode": "JK",
25+
"countryCode": "ID",
26+
"country": "Indonesia",
27+
"countryCodeISO3": "IDN",
28+
"freeformAddress": "Jakarta, Jakarta"
29+
},
30+
"position": {
31+
"lat": -6.17476,
32+
"lon": 106.82707
33+
},
34+
"viewport": {
35+
"topLeftPoint": {
36+
"lat": -5.95462, "lon": 106.68588
37+
},
38+
"btmRightPoint": {
39+
"lat": -6.37083, "lon": 106.9729
40+
}
41+
},
42+
"boundingBox": {
43+
"topLeftPoint": {
44+
"lat": -5.95462, "lon": 106.68588
45+
},
46+
"btmRightPoint": {
47+
"lat": -6.37083, "lon": 106.9729
48+
}
49+
},
50+
"dataSources": {
51+
"geometry": {
52+
"id": "00004944-3100-3c00-0000-000023c347ee"
53+
}
54+
}
55+
}
56+
]
57+
}
+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"summary": {
3+
"query": "madison square garden",
4+
"queryType": "NON_NEAR",
5+
"queryTime": 89,
6+
"numResults": 1,
7+
"offset": 0,
8+
"totalResults": 6,
9+
"fuzzyLevel": 1
10+
},
11+
"results": [
12+
{
13+
"type": "Street",
14+
"id": "QyS-HWGa0fkjABCOcS09Rw",
15+
"score": 0.8939382576343416,
16+
"matchConfidence": {
17+
"score": 0.8939382576343416
18+
},
19+
"address": {
20+
"streetName": "Garten Place",
21+
"municipality": "Madison Heights",
22+
"countrySecondarySubdivision": "Amherst",
23+
"countrySubdivision": "VA",
24+
"countrySubdivisionName": "Virginia",
25+
"countrySubdivisionCode": "VA",
26+
"postalCode": "24572",
27+
"extendedPostalCode": "24572-4418, 24572-4419",
28+
"countryCode": "US",
29+
"country": "United States",
30+
"countryCodeISO3": "USA",
31+
"freeformAddress": "Garten Place, Madison Heights, VA 24572",
32+
"localName": "Madison Heights"
33+
},
34+
"position": {
35+
"lat": 37.484629,
36+
"lon": -79.109597
37+
},
38+
"viewport": {
39+
"topLeftPoint": {
40+
"lat": 37.485,
41+
"lon": -79.11055
42+
},
43+
"btmRightPoint": {
44+
"lat": 37.48439,
45+
"lon": -79.10872
46+
}
47+
}
48+
}
49+
]
50+
}

test/fixtures/azure_no_results

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"summary": {
3+
"query": "Jakarta",
4+
"queryType": "NON_NEAR",
5+
"queryTime": 66,
6+
"numResults": 0,
7+
"offset": 0,
8+
"totalResults": 0,
9+
"fuzzyLevel": 1
10+
},
11+
"results": []
12+
}

test/fixtures/azure_reverse

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"summary": {
3+
"queryTime": 12,
4+
"numResults": 1
5+
},
6+
"addresses": [
7+
{
8+
"address": {
9+
"buildingNumber": "10",
10+
"streetNumber": "10",
11+
"routeNumbers": [],
12+
"street": "Jalan Mohammad Husni Thamrin",
13+
"streetName": "Jalan Mohammad Husni Thamrin",
14+
"streetNameAndNumber": "Jalan Mohammad Husni Thamrin 10",
15+
"countryCode": "ID",
16+
"countrySubdivision": "DKI Jakarta",
17+
"municipality": "Jakarta",
18+
"postalCode": "10230",
19+
"municipalitySecondarySubdivision": "Menteng",
20+
"country": "Indonesia",
21+
"countryCodeISO3": "IDN",
22+
"freeformAddress": "Jalan Mohammad Husni Thamrin 10, Kecamatan Jakarta, DKI Jakarta 10230",
23+
"boundingBox": {
24+
"northEast": "-6.198818,106.823264",
25+
"southWest": "-6.199555,106.823246",
26+
"entity": "position"
27+
},
28+
"countrySubdivisionName": "DKI Jakarta",
29+
"countrySubdivisionCode": "JK",
30+
"localName": "Jakarta"
31+
},
32+
"position": "-6.199203,106.823082",
33+
"id": "hlyQM4iHOYn16mWumCtnJA"
34+
}
35+
]
36+
}

0 commit comments

Comments
 (0)