diff --git a/Sources/AppleMapsKit/AppleMapsClient.swift b/Sources/AppleMapsKit/AppleMapsClient.swift index 6164910..4f6de2a 100644 --- a/Sources/AppleMapsKit/AppleMapsClient.swift +++ b/Sources/AppleMapsKit/AppleMapsClient.swift @@ -53,6 +53,7 @@ public struct AppleMapsClient: Sendable { userLocation: (latitude: Double, longitude: Double)? = nil ) async throws -> [Place] { var url = URL(string: "\(Self.apiServer)/v1/geocode")! + var queries: [URLQueryItem] = [URLQueryItem(name: "q", value: address)] if let limitToCountries { queries.append(URLQueryItem(name: "limitToCountries", value: limitToCountries.joined(separator: ","))) @@ -69,8 +70,10 @@ public struct AppleMapsClient: Sendable { if let userLocation { queries.append(URLQueryItem(name: "userLocation", value: "\(userLocation.latitude),\(userLocation.longitude)")) } + url.append(queryItems: queries) - return try await decoder.decode(PlaceResults.self, from: httpGet(url: url)).results ?? [] + + return try await self.decoder.decode(PlaceResults.self, from: self.httpGet(url: url)).results ?? [] } /// Returns an array of addresses present at the coordinates you provide. @@ -83,12 +86,15 @@ public struct AppleMapsClient: Sendable { /// - Returns: An array of one or more ``Place`` objects. public func reverseGeocode(latitude: Double, longitude: Double, lang: String? = nil) async throws -> [Place] { var url = URL(string: "\(Self.apiServer)/v1/reverseGeocode")! + var queries: [URLQueryItem] = [URLQueryItem(name: "loc", value: "\(latitude),\(longitude)")] if let lang { queries.append(URLQueryItem(name: "lang", value: lang)) } + url.append(queryItems: queries) - return try await decoder.decode(PlaceResults.self, from: httpGet(url: url)).results ?? [] + + return try await self.decoder.decode(PlaceResults.self, from: self.httpGet(url: url)).results ?? [] } /// Find places by name or by specific search criteria. @@ -129,6 +135,7 @@ public struct AppleMapsClient: Sendable { excludeAddressCategories: [AddressCategory]? = nil ) async throws -> SearchResponse { var url = URL(string: "\(Self.apiServer)/v1/search")! + var queries: [URLQueryItem] = [URLQueryItem(name: "q", value: place)] if let excludePoiCategories { queries.append( @@ -188,8 +195,10 @@ public struct AppleMapsClient: Sendable { URLQueryItem(name: "excludeAddressCategories", value: excludeAddressCategories.map { $0.rawValue }.joined(separator: ",")) ) } + url.append(queryItems: queries) - return try await decoder.decode(SearchResponse.self, from: httpGet(url: url)) + + return try await self.decoder.decode(SearchResponse.self, from: self.httpGet(url: url)) } /// Find results that you can use to autocomplete searches. @@ -226,6 +235,7 @@ public struct AppleMapsClient: Sendable { excludeAddressCategories: [AddressCategory]? = nil ) async throws -> [AutocompleteResult] { var url = URL(string: "\(Self.apiServer)/v1/searchAutocomplete")! + var queries: [URLQueryItem] = [URLQueryItem(name: "q", value: place)] if let excludePoiCategories { queries.append( @@ -268,8 +278,10 @@ public struct AppleMapsClient: Sendable { URLQueryItem(name: "excludeAddressCategories", value: excludeAddressCategories.map { $0.rawValue }.joined(separator: ",")) ) } + url.append(queryItems: queries) - return try await decoder.decode(SearchAutocompleteResponse.self, from: httpGet(url: url)).results ?? [] + + return try await self.decoder.decode(SearchAutocompleteResponse.self, from: self.httpGet(url: url)).results ?? [] } /// Find directions by specific criteria. @@ -306,6 +318,7 @@ public struct AppleMapsClient: Sendable { userLocation: (latitude: Double, longitude: Double)? = nil ) async throws -> DirectionsResponse { var url = URL(string: "\(Self.apiServer)/v1/directions")! + var queries: [URLQueryItem] = [ URLQueryItem(name: "origin", value: origin), URLQueryItem(name: "destination", value: destination), @@ -363,8 +376,10 @@ public struct AppleMapsClient: Sendable { if let userLocation { queries.append(URLQueryItem(name: "userLocation", value: "\(userLocation.latitude),\(userLocation.longitude)")) } + url.append(queryItems: queries) - return try await decoder.decode(DirectionsResponse.self, from: httpGet(url: url)) + + return try await self.decoder.decode(DirectionsResponse.self, from: self.httpGet(url: url)) } /// Returns the estimated time of arrival (ETA) and distance between starting and ending locations. @@ -387,6 +402,7 @@ public struct AppleMapsClient: Sendable { arrivalDate: Date? = nil ) async throws -> [Eta] { var url = URL(string: "\(Self.apiServer)/v1/etas")! + var queries: [URLQueryItem] = [ URLQueryItem(name: "origin", value: "\(origin.latitude),\(origin.longitude)"), URLQueryItem( @@ -429,8 +445,10 @@ public struct AppleMapsClient: Sendable { ) ) } + url.append(queryItems: queries) - return try await decoder.decode(EtaResponse.self, from: httpGet(url: url)).etas ?? [] + + return try await self.decoder.decode(EtaResponse.self, from: self.httpGet(url: url)).etas ?? [] } /// Returns the estimated time of arrival (ETA) and distance between starting and ending locations. @@ -454,11 +472,11 @@ public struct AppleMapsClient: Sendable { ) async throws -> [Eta] { var destinationCoordinates: [(latitude: Double, longitude: Double)] = [] for destination in destinations { - try await destinationCoordinates.append(getCoordinate(from: destination)) + try await destinationCoordinates.append(self.getCoordinate(from: destination)) } - return try await eta( - from: getCoordinate(from: origin), + return try await self.eta( + from: self.getCoordinate(from: origin), to: destinationCoordinates, transportType: transportType, departureDate: departureDate, @@ -474,13 +492,15 @@ public struct AppleMapsClient: Sendable { /// /// - Returns: A tuple representing coordinate. private func getCoordinate(from address: String) async throws -> (latitude: Double, longitude: Double) { - let places = try await geocode(address: address) + let places = try await self.geocode(address: address) + guard let coordinate = places.first?.coordinate, let latitude = coordinate.latitude, let longitude = coordinate.longitude else { throw AppleMapsKitError.noPlacesFound } + return (latitude, longitude) } @@ -496,7 +516,8 @@ public struct AppleMapsClient: Sendable { if let lang { url.append(queryItems: [URLQueryItem(name: "lang", value: lang)]) } - return try await decoder.decode(Place.self, from: httpGet(url: url)) + + return try await self.decoder.decode(Place.self, from: self.httpGet(url: url)) } /// Obtain a set of ``Place`` objects for a given set of Place IDs. @@ -508,12 +529,15 @@ public struct AppleMapsClient: Sendable { /// - Returns: A list of ``PlacesResponse`` results. public func places(ids: [String], lang: String? = nil) async throws -> PlacesResponse { var url = URL(string: "\(Self.apiServer)/v1/place")! + var queries: [URLQueryItem] = [URLQueryItem(name: "ids", value: ids.joined(separator: ","))] if let lang { queries.append(URLQueryItem(name: "lang", value: lang)) } + url.append(queryItems: queries) - return try await decoder.decode(PlacesResponse.self, from: httpGet(url: url)) + + return try await self.decoder.decode(PlacesResponse.self, from: self.httpGet(url: url)) } /// Get a list of alternate ``Place`` IDs given one or more Place IDs. @@ -524,7 +548,8 @@ public struct AppleMapsClient: Sendable { public func alternatePlaceIDs(ids: [String]) async throws -> AlternateIDsResponse { var url = URL(string: "\(Self.apiServer)/v1/place/alternateIds")! url.append(queryItems: [URLQueryItem(name: "ids", value: ids.joined(separator: ","))]) - return try await decoder.decode(AlternateIDsResponse.self, from: httpGet(url: url)) + + return try await self.decoder.decode(AlternateIDsResponse.self, from: self.httpGet(url: url)) } } @@ -538,17 +563,17 @@ extension AppleMapsClient { /// - Throws: Error response object. private func httpGet(url: URL) async throws -> ByteBuffer { var headers = HTTPHeaders() - headers.add(name: "Authorization", value: "Bearer \(try await authClient.accessToken)") + headers.add(name: "Authorization", value: "Bearer \(try await self.authClient.accessToken)") var request = HTTPClientRequest(url: url.absoluteString) request.headers = headers - let response = try await httpClient.execute(request, timeout: .seconds(30)) + let response = try await self.httpClient.execute(request, timeout: .seconds(30)) if response.status == .ok { return try await response.body.collect(upTo: 1024 * 1024) } else { - throw try await decoder.decode(ErrorResponse.self, from: response.body.collect(upTo: 1024 * 1024)) + throw try await self.decoder.decode(ErrorResponse.self, from: response.body.collect(upTo: 1024 * 1024)) } } } diff --git a/Sources/AppleMapsKit/AppleMapsKitError.swift b/Sources/AppleMapsKit/AppleMapsKitError.swift index 8352ca6..d8ba33c 100644 --- a/Sources/AppleMapsKit/AppleMapsKitError.swift +++ b/Sources/AppleMapsKit/AppleMapsKitError.swift @@ -16,7 +16,7 @@ public struct AppleMapsKitError: Error, Sendable { public static let invalidSearchResultType = Self(.invalidSearchResultType) public var description: String { - base.rawValue + self.base.rawValue } } @@ -42,6 +42,6 @@ public struct AppleMapsKitError: Error, Sendable { extension AppleMapsKitError: CustomStringConvertible { public var description: String { - "AppleMapsKitError(errorType: \(errorType))" + "AppleMapsKitError(errorType: \(self.errorType))" } } diff --git a/Sources/AppleMapsKit/Auth/AuthClient.swift b/Sources/AppleMapsKit/Auth/AuthClient.swift index 87ae101..a64d12c 100644 --- a/Sources/AppleMapsKit/Auth/AuthClient.swift +++ b/Sources/AppleMapsKit/Auth/AuthClient.swift @@ -1,10 +1,3 @@ -// -// AuthClient.swift -// apple-maps-kit -// -// Created by FarouK on 11/10/2024. -// - import AsyncHTTPClient import Foundation import JWTKit @@ -35,7 +28,7 @@ actor AuthClient { // If we don't have a current token, we request a new one. guard let currentToken else { - return try await newToken + return try await self.newToken } if currentToken.isValid { @@ -43,7 +36,7 @@ actor AuthClient { } // None of the above applies so we'll need to refresh the token. - return try await newToken + return try await self.newToken } } @@ -56,13 +49,13 @@ actor AuthClient { // If we don't have a current token, we request a new one. let task = Task { () throws -> TokenResponse in - defer { refreshTask = nil } - let newToken = try await tokenResponse - currentToken = newToken + defer { self.refreshTask = nil } + let newToken = try await self.tokenResponse + self.currentToken = newToken return newToken } - refreshTask = task + self.refreshTask = task return try await task.value.accessToken } } @@ -72,7 +65,7 @@ extension AuthClient { private var tokenResponse: TokenResponse { get async throws { var headers = HTTPHeaders() - headers.add(name: "Authorization", value: "Bearer \(try await jwtToken)") + headers.add(name: "Authorization", value: "Bearer \(try await self.jwtToken)") var request = HTTPClientRequest(url: "\(AppleMapsClient.apiServer)/v1/token") request.headers = headers diff --git a/Sources/AppleMapsKit/Auth/TokenResponse.swift b/Sources/AppleMapsKit/Auth/TokenResponse.swift index c9483ef..0209a87 100644 --- a/Sources/AppleMapsKit/Auth/TokenResponse.swift +++ b/Sources/AppleMapsKit/Auth/TokenResponse.swift @@ -26,9 +26,10 @@ struct TokenResponse: Codable { } extension TokenResponse { + /// A boolean value that indicates if the token is valid. + /// + /// We consider a token invalid 10 seconds before it actual expiry time, so we have some time to refresh it. var isValid: Bool { - // We consider a token invalid 10 seconds before it actual expiry time, - // so we have some time to refresh it. - return Date.now < (expirationDate - 10) + Date.now < (expirationDate - 10) } } diff --git a/Sources/AppleMapsKit/DTOs/ErrorResponse.swift b/Sources/AppleMapsKit/DTOs/ErrorResponse.swift index fbf18b9..e72f6f3 100644 --- a/Sources/AppleMapsKit/DTOs/ErrorResponse.swift +++ b/Sources/AppleMapsKit/DTOs/ErrorResponse.swift @@ -9,7 +9,7 @@ public struct ErrorResponse: Error, Codable, Sendable { extension ErrorResponse: CustomStringConvertible { public var description: String { - var result = #"AppleMapsError(message: \#(message ?? "nil")"# + var result = #"AppleMapsError(message: \#(self.message ?? "nil")"# if let details { result.append(", details: \(details)") diff --git a/Sources/AppleMapsKit/DTOs/MapRegion.swift b/Sources/AppleMapsKit/DTOs/MapRegion.swift index 188a042..b09baa3 100644 --- a/Sources/AppleMapsKit/DTOs/MapRegion.swift +++ b/Sources/AppleMapsKit/DTOs/MapRegion.swift @@ -25,10 +25,10 @@ public struct MapRegion: Codable, Sendable { } var toString: String? { - guard let northLatitude = northLatitude, - let eastLongitude = eastLongitude, - let southLatitude = southLatitude, - let westLongitude = westLongitude + guard let northLatitude, + let eastLongitude, + let southLatitude, + let westLongitude else { return nil } diff --git a/Tests/AppleMapsKitTests/AuthTests.swift b/Tests/AppleMapsKitTests/AuthTests.swift index 20bffe8..fd83ad8 100644 --- a/Tests/AppleMapsKitTests/AuthTests.swift +++ b/Tests/AppleMapsKitTests/AuthTests.swift @@ -1,10 +1,3 @@ -// -// AuthTests.swift -// apple-maps-kit -// -// Created by FarouK on 12/10/2024. -// - import Foundation import Testing