mapricot-api 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +16 -14
  3. data/lib/mapricot/api.rb +86 -50
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24849159506d71db67b1e674bf3cf9377f218c78260002730a2f1dab55b713f9
4
- data.tar.gz: '07499083f22bd04f51f65704bb24e204c0f7767564e84de4f92114c6836aa09e'
3
+ metadata.gz: 85ceb14ed10d1d3499221e1e2f4378cd3e40c58b4b3274e341004452bc873518
4
+ data.tar.gz: 3a01af9ed6d7431e07255bb635e09d77dd01232c613b9a469da9815d601cd659
5
5
  SHA512:
6
- metadata.gz: 1b921d6fabb89653dbde12a181390f618e547dada82ea5587108d2e0acc069d8b43e1c427d30d96cf1abe2807933b670462f779aebe4e4499b0b20c23a045b13
7
- data.tar.gz: e1f406517e97e473fcc7eece8890e609d26c2921523cb88e18c23f72bc84258d553e540b9e9724d883b057722c6137fd79327b04e75fb72b5d331de1e569dc88
6
+ metadata.gz: 46a943e94e0f8c2d0d22ddb9d1f7857034b6599fa87633ddbf3d71b982172abf70f096edfbf560b139a0f7a00708d0ef8f5c9a85e2bd97671ec7268c391f8eb1
7
+ data.tar.gz: e5d5becbf5f3de0301f40963ef84317efde3f606ebca3a90050a2c2e98ec23ba3d631e54274f5f3c97fd0aeda837a9a69328bec76c2ff5c872152b1347f98779
data/README.md CHANGED
@@ -17,41 +17,43 @@ require "mapricot/api"
17
17
 
18
18
  client = Mapricot::Client.new(api_key: ENV.fetch("MAPRICOT_KEY"))
19
19
 
20
- data = client.search("128 SW 3rd Ave, Portland", limit: 1)
20
+ data = client.geocoding.search("128 SW 3rd Ave, Portland", limit: 1)
21
21
  place = data["results"][0]
22
22
  puts place["label"], place["lat"], place["lon"]
23
23
  ```
24
24
 
25
25
  ## Methods
26
26
 
27
- Each method returns the API's JSON as a Hash with string keys, with the same field names as the [API reference](https://mapricot.com/api-reference/).
27
+ Methods are grouped by product, the same way as the API's paths. Each returns the API's JSON as a Hash with string keys, with the same field names as the [API reference](https://mapricot.com/api-reference/).
28
28
 
29
29
  | Method | Endpoint |
30
30
  | --- | --- |
31
- | `client.search(q, focus:, country:, limit:, lang:)` | [`GET /geocoding/v1/search`](https://mapricot.com/docs/geocoding/#find-an-address) |
32
- | `client.autocomplete(q, focus:, country:, limit:, lang:)` | [`GET /geocoding/v1/autocomplete`](https://mapricot.com/docs/geocoding/#suggest-as-people-type) |
33
- | `client.reverse(lat, lon, limit:, lang:)` | [`GET /geocoding/v1/reverse`](https://mapricot.com/docs/geocoding/#find-the-address-at-a-point) |
34
- | `client.nearby(lat, lon, category:, radius:, limit:, lang:)` | [`GET /places/v1/nearby`](https://mapricot.com/docs/places/#list-places-around-a-point) |
35
- | `client.place(id, lang:)` | [`GET /places/v1/{id}`](https://mapricot.com/docs/places/#look-up-a-saved-place) |
36
- | `client.route(waypoints, mode:, geometries:)` | [`POST /routing/v1/route`](https://mapricot.com/docs/routing/#get-a-route) |
37
- | `client.isochrone(location, minutes, mode:)` | [`POST /routing/v1/isochrone`](https://mapricot.com/docs/routing/#get-an-isochrone) |
38
- | `client.ip(address)` | [`GET /ip-geolocation/v1/{ip}`](https://mapricot.com/docs/ip-geolocation/#look-up-an-address) |
31
+ | `client.geocoding.search(q, focus:, country:, limit:, lang:)` | [`GET /geocoding/v1/search`](https://mapricot.com/docs/geocoding/#find-an-address) |
32
+ | `client.geocoding.autocomplete(q, focus:, country:, limit:, lang:)` | [`GET /geocoding/v1/autocomplete`](https://mapricot.com/docs/geocoding/#suggest-as-people-type) |
33
+ | `client.geocoding.reverse(lat, lon, limit:, lang:)` | [`GET /geocoding/v1/reverse`](https://mapricot.com/docs/geocoding/#find-the-address-at-a-point) |
34
+ | `client.places.nearby(lat, lon, category:, radius:, limit:, lang:)` | [`GET /places/v1/nearby`](https://mapricot.com/docs/places/#list-places-around-a-point) |
35
+ | `client.places.get(id, lang:)` | [`GET /places/v1/{id}`](https://mapricot.com/docs/places/#look-up-a-saved-place) |
36
+ | `client.routing.route(waypoints, mode:, geometries:, steps:, lang:)` | [`POST /routing/v1/route`](https://mapricot.com/docs/routing/#get-a-route) |
37
+ | `client.routing.isochrone(location, minutes, mode:)` | [`POST /routing/v1/isochrone`](https://mapricot.com/docs/routing/#get-an-isochrone) |
38
+ | `client.ip_geolocation.lookup(ip)` | [`GET /ip-geolocation/v1/{ip}`](https://mapricot.com/docs/ip-geolocation/#look-up-an-address) |
39
39
  | `client.account` | `GET /account`, which checks a key and is never billed |
40
40
 
41
41
  Every keyword argument is optional. `focus` and each waypoint are `{ lat:, lon: }`. `country` and `category` take an Array or a comma-separated String.
42
42
 
43
43
  ```ruby
44
- nearby = client.nearby(45.52, -122.68, category: ["food:coffee_shop"], radius: 1000)
45
- route = client.route([{ lat: 45.5189, lon: -122.6793 }, { lat: 45.5214, lon: -122.6828 }], mode: "walk")
44
+ nearby = client.places.nearby(45.52, -122.68, category: ["food:coffee_shop"], radius: 1000)
45
+ route = client.routing.route([{ lat: 45.5189, lon: -122.6793 }, { lat: 45.5214, lon: -122.6828 }], mode: "walk")
46
46
  puts route["routes"][0]["durationSeconds"]
47
47
  ```
48
48
 
49
49
  A route's path comes as an encoded `polyline` with five decimal places, which polyline decoders assume. Pass `geometries: "geojson"` to get it as a GeoJSON `LineString` in `geometry` instead, which maps draw without decoding, or `geometries: "polyline6"` for six decimal places.
50
50
 
51
+ Pass `steps: true` and each leg's `steps` has its turn-by-turn directions: an `instruction`, its distance and time, and its `lat` and `lon`. They're in English unless you pass `lang`, such as `lang: "fr"`.
52
+
51
53
  An isochrone is a GeoJSON `FeatureCollection` with one polygon per time, largest first, so a map that draws them in order shows the smaller ones on top:
52
54
 
53
55
  ```ruby
54
- area = client.isochrone({ lat: 45.5189, lon: -122.6793 }, [5, 10], mode: "walk")
56
+ area = client.routing.isochrone({ lat: 45.5189, lon: -122.6793 }, [5, 10], mode: "walk")
55
57
  puts area["features"].map { |feature| feature["properties"]["minutes"] }.inspect
56
58
  ```
57
59
 
@@ -63,7 +65,7 @@ An error response raises `Mapricot::Error`, with the HTTP `status`, the API's er
63
65
 
64
66
  ```ruby
65
67
  begin
66
- client.search("")
68
+ client.geocoding.search("")
67
69
  rescue Mapricot::Error => e
68
70
  puts e.status, e.code, e.message # 400, invalid_request, The service rejected the request.
69
71
  end
data/lib/mapricot/api.rb CHANGED
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "erb"
3
4
  require "json"
4
5
  require "net/http"
5
6
 
6
7
  # The official client for the Mapricot API: address and place search, reverse geocoding, nearby places, routing,
7
8
  # and IP geolocation. See https://mapricot.com/docs/ruby/.
8
9
  module Mapricot
9
- VERSION = "0.5.0"
10
+ VERSION = "0.7.0"
10
11
 
11
12
  # An error response from the API.
12
13
  class Error < StandardError
@@ -20,8 +21,11 @@ module Mapricot
20
21
  end
21
22
  end
22
23
 
23
- # Each method returns the API's JSON as a Hash with string keys, as in https://mapricot.com/api-reference/.
24
+ # Methods are grouped by product, as in client.geocoding.search. Each returns the API's JSON as a Hash with string
25
+ # keys, as in https://mapricot.com/api-reference/.
24
26
  class Client
27
+ attr_reader :geocoding, :places, :routing, :ip_geolocation
28
+
25
29
  def initialize(api_key:, base_url: "https://api.mapricot.com", timeout: 30, max_retries: 2)
26
30
  raise ArgumentError, "Pass api_key:, a Mapricot key." if api_key.nil? || api_key.empty?
27
31
 
@@ -29,50 +33,10 @@ module Mapricot
29
33
  @base_url = base_url
30
34
  @timeout = timeout
31
35
  @max_retries = max_retries
32
- end
33
-
34
- # Find addresses and places matching free text. focus is {lat:, lon:}; country is an Array or a String.
35
- def search(q, focus: nil, country: nil, limit: nil, lang: nil)
36
- get("/geocoding/v1/search", q: q, focus: focus, country: country, limit: limit, lang: lang)
37
- end
38
-
39
- # Suggest addresses and places as someone types.
40
- def autocomplete(q, focus: nil, country: nil, limit: nil, lang: nil)
41
- get("/geocoding/v1/autocomplete", q: q, focus: focus, country: country, limit: limit, lang: lang)
42
- end
43
-
44
- # Find the address nearest a coordinate, or the area around it.
45
- def reverse(lat, lon, limit: nil, lang: nil)
46
- get("/geocoding/v1/reverse", lat: lat, lon: lon, limit: limit, lang: lang)
47
- end
48
-
49
- # List places around a coordinate, optionally by category, an Array or a String.
50
- def nearby(lat, lon, category: nil, radius: nil, limit: nil, lang: nil)
51
- get("/places/v1/nearby", lat: lat, lon: lon, category: category, radius: radius, limit: limit, lang: lang)
52
- end
53
-
54
- # Look up one place by its Mapricot ID.
55
- def place(id, lang: nil)
56
- get("/places/v1/#{escape(id)}", lang: lang)
57
- end
58
-
59
- # Find a route through 2 to 20 waypoints, each {lat:, lon:}. mode is "drive" (the default), "walk", or "bicycle".
60
- # geometries is "polyline" (the default), "polyline6", or "geojson".
61
- def route(waypoints, mode: nil, geometries: nil)
62
- body = { waypoints: waypoints, mode: mode, geometries: geometries }.compact
63
- request(Net::HTTP::Post, URI("#{@base_url}/routing/v1/route"), JSON.generate(body))
64
- end
65
-
66
- # The areas reachable from a location, {lat:, lon:}, within 1 to 4 times, each 1 to 60 minutes, as a GeoJSON
67
- # FeatureCollection with one polygon per time, largest first. mode is as for route.
68
- def isochrone(location, minutes, mode: nil)
69
- body = { location: location, minutes: minutes, mode: mode }.compact
70
- request(Net::HTTP::Post, URI("#{@base_url}/routing/v1/isochrone"), JSON.generate(body))
71
- end
72
-
73
- # Approximate location of a public IP address.
74
- def ip(address)
75
- get("/ip-geolocation/v1/#{escape(address)}")
36
+ @geocoding = GeocodingService.new(method(:get))
37
+ @places = PlacesService.new(method(:get))
38
+ @routing = RoutingService.new(method(:post))
39
+ @ip_geolocation = IpGeolocationService.new(method(:get))
76
40
  end
77
41
 
78
42
  # The key's account. Not billed, so it checks a key for free.
@@ -89,6 +53,10 @@ module Mapricot
89
53
  request(Net::HTTP::Get, uri)
90
54
  end
91
55
 
56
+ def post(path, body)
57
+ request(Net::HTTP::Post, URI(@base_url + path), JSON.generate(body.compact))
58
+ end
59
+
92
60
  def request(method, uri, body = nil)
93
61
  attempt = 0
94
62
  loop do
@@ -121,10 +89,6 @@ module Mapricot
121
89
  end
122
90
  end
123
91
 
124
- def escape(segment)
125
- URI.encode_www_form_component(segment).gsub("+", "%20")
126
- end
127
-
128
92
  def error_from(response)
129
93
  request_id = response["X-Request-Id"]
130
94
  error = JSON.parse(response.body).fetch("error")
@@ -137,4 +101,76 @@ module Mapricot
137
101
  error.status == 503 || error.code == "concurrency_exceeded"
138
102
  end
139
103
  end
104
+
105
+ # client.geocoding: the /geocoding/v1 endpoints.
106
+ class GeocodingService
107
+ def initialize(get)
108
+ @get = get
109
+ end
110
+
111
+ # Find addresses and places matching free text. focus is {lat:, lon:}; country is an Array or a String.
112
+ def search(q, focus: nil, country: nil, limit: nil, lang: nil)
113
+ @get.call("/geocoding/v1/search", q: q, focus: focus, country: country, limit: limit, lang: lang)
114
+ end
115
+
116
+ # Suggest addresses and places as someone types.
117
+ def autocomplete(q, focus: nil, country: nil, limit: nil, lang: nil)
118
+ @get.call("/geocoding/v1/autocomplete", q: q, focus: focus, country: country, limit: limit, lang: lang)
119
+ end
120
+
121
+ # Find the address nearest a coordinate, or the area around it.
122
+ def reverse(lat, lon, limit: nil, lang: nil)
123
+ @get.call("/geocoding/v1/reverse", lat: lat, lon: lon, limit: limit, lang: lang)
124
+ end
125
+ end
126
+
127
+ # client.places: the /places/v1 endpoints.
128
+ class PlacesService
129
+ def initialize(get)
130
+ @get = get
131
+ end
132
+
133
+ # List places around a coordinate, optionally by category, an Array or a String.
134
+ def nearby(lat, lon, category: nil, radius: nil, limit: nil, lang: nil)
135
+ @get.call("/places/v1/nearby", lat: lat, lon: lon, category: category, radius: radius, limit: limit, lang: lang)
136
+ end
137
+
138
+ # Look up one place by its Mapricot ID.
139
+ def get(id, lang: nil)
140
+ @get.call("/places/v1/#{ERB::Util.url_encode(id)}", lang: lang)
141
+ end
142
+ end
143
+
144
+ # client.routing: the /routing/v1 endpoints.
145
+ class RoutingService
146
+ def initialize(post)
147
+ @post = post
148
+ end
149
+
150
+ # Find a route through 2 to 20 waypoints, each {lat:, lon:}. mode is "drive" (the default), "walk", or "bicycle".
151
+ # geometries is "polyline" (the default), "polyline6", or "geojson". steps: true adds each leg's turn-by-turn
152
+ # steps, in lang, an ISO 639-1 language, English by default.
153
+ def route(waypoints, mode: nil, geometries: nil, steps: nil, lang: nil)
154
+ body = { waypoints: waypoints, mode: mode, geometries: geometries, steps: steps, lang: lang }
155
+ @post.call("/routing/v1/route", body)
156
+ end
157
+
158
+ # The areas reachable from a location, {lat:, lon:}, within 1 to 4 times, each 1 to 60 minutes, as a GeoJSON
159
+ # FeatureCollection with one polygon per time, largest first. mode is as for route.
160
+ def isochrone(location, minutes, mode: nil)
161
+ @post.call("/routing/v1/isochrone", { location: location, minutes: minutes, mode: mode })
162
+ end
163
+ end
164
+
165
+ # client.ip_geolocation: the /ip-geolocation/v1 endpoints.
166
+ class IpGeolocationService
167
+ def initialize(get)
168
+ @get = get
169
+ end
170
+
171
+ # Approximate location of a public IP address.
172
+ def lookup(ip)
173
+ @get.call("/ip-geolocation/v1/#{ERB::Util.url_encode(ip)}")
174
+ end
175
+ end
140
176
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mapricot-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mapricot