Skip to content

Commit 75e3744

Browse files
Fix batch geocoding request handling (#148)
* Allowing batch geocoding of at least one query * Refactor mode override * Handle multiple geocoding queries * Add clarifying comments * Minor feedback edits * Set up single forward batch test case * Add test for valid fwd batch geocoding with multiple queries * Add test for failed single forward batch geocode * Add test for failed multiple forward batch geocode * Add debug notes * Add no-results returned forward batch geocoding tests * Rename/cleanup tests & comments * Switch from guard to if/let * Add reverse batch geocode tests * Match precision for path-matching tests * Fix test fixture file paths * 🔮
1 parent a6a4153 commit 75e3744

15 files changed

+2707
-13
lines changed

MapboxGeocoder.xcodeproj/project.pbxproj

Lines changed: 96 additions & 0 deletions
Large diffs are not rendered by default.

MapboxGeocoder/MBGeocodeOptions.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ open class GeocodeOptions: NSObject {
8080
*/
8181
internal var queries: [String] = []
8282

83+
/**
84+
The query mode of the forward or reverse geocoding request.
85+
*/
86+
internal var mode = "mapbox.places"
87+
8388
/**
8489
An array of URL parameters to include in the request URL.
8590
*/
@@ -221,6 +226,7 @@ open class ForwardBatchGeocodeOptions: ForwardGeocodeOptions, BatchGeocodeOption
221226
*/
222227
@objc public override init(queries: [String]) {
223228
super.init(queries: queries)
229+
mode = "mapbox.places-permanent"
224230
}
225231
}
226232

@@ -236,6 +242,7 @@ open class ReverseBatchGeocodeOptions: ReverseGeocodeOptions, BatchGeocodeOption
236242
*/
237243
@objc public override init(coordinates: [CLLocationCoordinate2D]) {
238244
super.init(coordinates: coordinates)
245+
mode = "mapbox.places-permanent"
239246
}
240247

241248
/**
@@ -245,5 +252,6 @@ open class ReverseBatchGeocodeOptions: ReverseGeocodeOptions, BatchGeocodeOption
245252
*/
246253
@objc public convenience init(locations: [CLLocation]) {
247254
self.init(coordinates: locations.map { $0.coordinate })
255+
mode = "mapbox.places-permanent"
248256
}
249257
}

MapboxGeocoder/MBGeocoder.swift

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,17 @@ open class Geocoder: NSObject {
223223
let decoder = JSONDecoder()
224224

225225
do {
226-
let result = try decoder.decode([GeocodeResult].self, from: data)
226+
227+
let result: [GeocodeResult]
228+
229+
do {
230+
// Decode multiple batch geocoding queries
231+
result = try decoder.decode([GeocodeResult].self, from: data)
232+
} catch {
233+
// Decode single batch geocding queries
234+
result = [try decoder.decode(GeocodeResult.self, from: data)]
235+
}
236+
227237
let placemarks = result.map { $0.placemarks }
228238
let attributionsByQuery = result.map { $0.attribution }
229239
completionHandler(placemarks, attributionsByQuery, nil)
@@ -250,16 +260,20 @@ open class Geocoder: NSObject {
250260
*/
251261
fileprivate func dataTaskWithURL(_ url: URL, completionHandler: @escaping (_ data: Data?) -> Void, errorHandler: @escaping (_ error: NSError) -> Void) -> URLSessionDataTask {
252262
var request = URLRequest(url: url)
263+
253264
request.setValue(userAgent, forHTTPHeaderField: "User-Agent")
254265
return URLSession.shared.dataTask(with: request) { (data, response, error) in
255266

256267
guard let data = data else { return }
257268
let decoder = JSONDecoder()
258269

259270
do {
260-
let result = try decoder.decode(GeocodeAPIResult.self, from: data)
261-
guard result.message == nil else {
262-
let apiError = Geocoder.descriptiveError(["message": result.message!], response: response, underlyingError: error as NSError?)
271+
// Handle multiple batch geocoding queries
272+
let result = try decoder.decode([GeocodeAPIResult].self, from: data)
273+
274+
// Check if any of the batch geocoding queries failed
275+
if let failedResult = result.first(where: { $0.message != nil }) {
276+
let apiError = Geocoder.descriptiveError(["message": failedResult.message!], response: response, underlyingError: error as NSError?)
263277
DispatchQueue.main.async {
264278
errorHandler(apiError)
265279
}
@@ -269,8 +283,26 @@ open class Geocoder: NSObject {
269283
completionHandler(data)
270284
}
271285
} catch {
272-
DispatchQueue.main.async {
273-
errorHandler(error as NSError)
286+
// Handle single & single batch geocoding queries
287+
do {
288+
let result = try decoder.decode(GeocodeAPIResult.self, from: data)
289+
// Check if geocoding query failed
290+
if let message = result.message {
291+
let apiError = Geocoder.descriptiveError(["message": message], response: response, underlyingError: error as NSError?)
292+
DispatchQueue.main.async {
293+
errorHandler(apiError)
294+
}
295+
return
296+
297+
}
298+
DispatchQueue.main.async {
299+
completionHandler(data)
300+
}
301+
} catch {
302+
// Handle errors that don't return a message (such as a server/network error)
303+
DispatchQueue.main.async {
304+
errorHandler(error as NSError)
305+
}
274306
}
275307
}
276308
}
@@ -290,13 +322,7 @@ open class Geocoder: NSObject {
290322

291323
assert(!options.queries.isEmpty, "No query")
292324

293-
let mode: String
294-
if options.queries.count > 1 {
295-
mode = "mapbox.places-permanent"
296-
assert(options.queries.count <= 50, "Too many queries in a single request.")
297-
} else {
298-
mode = "mapbox.places"
299-
}
325+
let mode = options.mode
300326

301327
let queryComponent = options.queries.map {
302328
$0.replacingOccurrences(of: " ", with: "+")

0 commit comments

Comments
 (0)