@@ -30,158 +30,120 @@ open class Service
3030 {
3131 /// Returned when the `URLComponents` structure fails to initialize, most likely because of the `query` parameter.
3232 case invalidURL
33-
3433 /// Return when the `URLComponents` structure fails to create a valid `URL`.
3534 case malformedURL
36-
3735 /// Returned when the request data is invalid.
3836 case invalidRequestData
39-
4037 /// Returned when the server response contained invalid data.
4138 case invalidResponseData
4239 }
4340
4441 /// This is the status type returned by IPAPI.
45- public enum Status : String
42+ public enum Status : String , Codable
4643 {
4744 /// Returned when the server is unable to process the request.
4845 case fail
49-
5046 /// Returned when the request has succeeded.
5147 case success
5248 }
5349
54- /// This is the field type used by the IPAPI service to filter out unnecessary data.
55- public enum Field : String
56- {
57- /// AS number and name.
58- case `as` = " as "
59-
60- /// City.
61- case city
62-
63- /// Country code short.
64- case countryCode
65-
66- /// Country name.
67- case countryName = " country "
68-
69- /// IP.
70- case ip = " query "
71-
72- /// Internet Service Provider name.
73- case isp
74-
75- /// Latitude.
76- case latitude = " lat "
77-
78- /// Longitude.
79- case longitude = " lon "
80-
81- /// Error message.
82- case message
83-
84- /// Mobile (cellular) connection.
85- case mobile
86-
87- /// Organization name.
88- case organization = " org "
89-
90- /// Proxy (anonymous).
91- case proxy
92-
93- /// Region/State code short.
94- case regionCode = " region "
95-
96- /// Region/State name.
97- case regionName
98-
99- /// Reverse DNS of the IP.
100- case reverse
101-
102- /// Status.
103- case status
104-
105- /// Timezone.
106- case timezone
107-
108- /// Zip code.
109- case zipCode = " zip "
110-
111- /// Returns an `Array` with all the fields.
112- public static var all : [ Field ] {
113- return [ . `as`, . city, . countryCode, . countryName, . ip, . isp, . latitude, . longitude, . message, . mobile,
114- . organization, . proxy, . regionCode, . regionName, . reverse, . status, . timezone, . zipCode]
115- }
116- }
117-
11850 /// This is the result type returned by IPAPI.
119- public struct Result
51+ public struct Result : Codable
12052 {
12153 /// AS number and name, separated by space. Example: `"AS15169 Google Inc."`
12254 public var `as` : String ?
123-
12455 /// City. Example: `"Mountain View"`
12556 public var city : String ?
126-
12757 /// Country code short. Example: `"US"`
12858 public var countryCode : String ?
129-
13059 /// Country name. Example: `"United States"`
13160 public var countryName : String ?
132-
13361 /// IP used for the query. Example: `"173.194.67.94"`
13462 public var ip : String ?
135-
13663 /// Internet Service Provider name. Example: `"Google"`
13764 public var isp : String ?
138-
13965 /// Latitude. Example: `37.4192`
14066 public var latitude : Double ?
141-
14267 /// Longitude. Example: `-122.0574`
14368 public var longitude : Double ?
144-
14569 /// Error message. Example: `"reserved range"`
14670 public var message : String ?
147-
14871 /// Mobile (cellular) connection. Example: `true`
14972 public var mobile : Bool ?
150-
15173 /// Organization name. Example: `"Google"`
15274 public var organization : String ?
153-
15475 /// Proxy (anonymous). Example: `true`
15576 public var proxy : Bool ?
156-
15777 /// Region/State code short. Example: `"CA"` or `"10"`
15878 public var regionCode : String ?
159-
16079 /// Region/State name. Example: `"California"`
16180 public var regionName : String ?
162-
16381 /// Reverse DNS of the IP. Example: `"wi-in-f94.1e100.net"`
16482 public var reverse : String ?
165-
16683 /// Status. Example: `success`
16784 public var status : Status ?
168-
16985 /// Timezone. Example: `"America/Los_Angeles"`
17086 public var timezone : String ?
171-
17287 /// Zip code. Example: `"94043"`
17388 public var zipCode : String ?
89+
90+ /// This is the field type used by the IPAPI service to filter out unnecessary data.
91+ public enum CodingKeys : String , CodingKey {
92+ /// AS number and name.
93+ case `as` = " as "
94+ /// City.
95+ case city
96+ /// Country code short.
97+ case countryCode
98+ /// Country name.
99+ case countryName = " country "
100+ /// IP.
101+ case ip = " query "
102+ /// Internet Service Provider name.
103+ case isp
104+ /// Latitude.
105+ case latitude = " lat "
106+ /// Longitude.
107+ case longitude = " lon "
108+ /// Error message.
109+ case message
110+ /// Mobile (cellular) connection.
111+ case mobile
112+ /// Organization name.
113+ case organization = " org "
114+ /// Proxy (anonymous).
115+ case proxy
116+ /// Region/State code short.
117+ case regionCode = " region "
118+ /// Region/State name.
119+ case regionName
120+ /// Reverse DNS of the IP.
121+ case reverse
122+ /// Status.
123+ case status
124+ /// Timezone.
125+ case timezone
126+ /// Zip code.
127+ case zipCode = " zip "
128+
129+ /// Returns an `Array` with all the fields.
130+ public static var all : [ CodingKeys ] {
131+ return [ . `as`, . city, . countryCode, . countryName, . ip, . isp, . latitude, . longitude, . message, . mobile,
132+ . organization, . proxy, . regionCode, . regionName, . reverse, . status, . timezone, . zipCode]
133+ }
134+ }
135+
136+ /// This is the typical JSON type used by webservices.
137+ public typealias Field = CodingKeys
174138 }
175139
176140 /// This is the request type used by the `batch` method.
177141 public struct Request
178142 {
179143 /// The IP address to lookup. This parameter is required.
180144 public var query : String
181-
182145 /// If you don't require all the returned fields use this property to specify which fields to return. *Tip: Disabling* `reverse` *may improve performance*. This parameter is optional.
183- public var fields : [ Field ] ? = nil
184-
146+ public var fields : [ Result . Field ] ? = nil
185147 /// Localized `city`, `regionName` and `countryName` can be requested by using this property in the `ISO 639` format. This parameter is optional.
186148 public var language : String ? = nil
187149
@@ -195,7 +157,7 @@ open class Service
195157 /// - language: The language to use for the city, region and country names.
196158 ///
197159 /// - Returns: The new `Request` instance.
198- init ( query: String , fields: [ Field ] ? = nil , language: String ? = nil ) {
160+ init ( query: String , fields: [ Result . Field ] ? = nil , language: String ? = nil ) {
199161 self . query = query
200162 self . fields = fields
201163 self . language = language
@@ -247,7 +209,7 @@ open class Service
247209 /// - language: Localized `city`, `regionName` and `countryName` can be requested by using this property in the `ISO 639` format.
248210 /// - completion: A closure that will be called upon completion.
249211 /// - Returns: The new `URLSessionDataTask` instance.
250- @discardableResult open func fetch( query: String ? = nil , fields: [ Field ] ? = nil , language: String ? = nil , completion: ( ( _ result: Result ? , _ error: Swift . Error ? ) -> Void ) ? ) -> URLSessionDataTask ?
212+ @discardableResult open func fetch( query: String ? = nil , fields: [ Result . Field ] ? = nil , language: String ? = nil , completion: ( ( _ result: Result ? , _ error: Swift . Error ? ) -> Void ) ? ) -> URLSessionDataTask ?
251213 {
252214 var urlString = " \( type ( of: self ) . baseURLString) /json "
253215 if let query = query {
@@ -283,8 +245,8 @@ open class Service
283245 if let error = error {
284246 completion ? ( nil , error)
285247 } else {
286- if let data = data , let object = try ? JSONSerialization . jsonObject ( with : data , options : [ ] ) , let json = object as? JSON {
287- let result = Result ( json : json )
248+ let decoder = JSONDecoder ( )
249+ if let data = data , let result = try ? decoder . decode ( Result . self , from : data ) {
288250 completion ? ( result, nil )
289251 } else {
290252 completion ? ( nil , Error . invalidResponseData)
@@ -333,8 +295,8 @@ open class Service
333295 if let error = error {
334296 completion ? ( nil , error)
335297 } else {
336- if let data = data , let object = try ? JSONSerialization . jsonObject ( with : data , options : [ ] ) , let json = object as? [ JSON ] {
337- let result = json . flatMap { Result ( json : $0 ) }
298+ let decoder = JSONDecoder ( )
299+ if let data = data , let result = try ? decoder . decode ( [ Result ] . self , from : data ) {
338300 completion ? ( result, nil )
339301 } else {
340302 completion ? ( nil , Error . invalidResponseData)
@@ -348,79 +310,6 @@ open class Service
348310
349311}
350312
351- //
352- // # Result: JSON Extension
353- //
354-
355- public extension Service . Result
356- {
357-
358- // MARK: - Deserialization -
359-
360- /// Initializes the `Result` instance with a given JSON object.
361- ///
362- /// - Parameters:
363- /// - json: The JSON object.
364- ///
365- /// - Returns: The new `Result` instance.
366- init ? ( json: Service . JSON )
367- {
368- let statusString = json [ Service . Field. status. rawValue] as? String
369-
370- self . `as` = json [ Service . Field. `as`. rawValue] as? String
371- self . city = json [ Service . Field. city. rawValue] as? String
372- self . countryCode = json [ Service . Field. countryCode. rawValue] as? String
373- self . countryName = json [ Service . Field. countryName. rawValue] as? String
374- self . ip = json [ Service . Field. ip. rawValue] as? String
375- self . isp = json [ Service . Field. isp. rawValue] as? String
376- self . latitude = json [ Service . Field. latitude. rawValue] as? Double
377- self . longitude = json [ Service . Field. longitude. rawValue] as? Double
378- self . message = json [ Service . Field. message. rawValue] as? String
379- self . mobile = json [ Service . Field. mobile. rawValue] as? Bool
380- self . organization = json [ Service . Field. organization. rawValue] as? String
381- self . proxy = json [ Service . Field. proxy. rawValue] as? Bool
382- self . regionCode = json [ Service . Field. regionCode. rawValue] as? String
383- self . regionName = json [ Service . Field. regionName. rawValue] as? String
384- self . reverse = json [ Service . Field. reverse. rawValue] as? String
385- self . timezone = json [ Service . Field. timezone. rawValue] as? String
386- self . zipCode = json [ Service . Field. zipCode. rawValue] as? String
387-
388- if let statusString = statusString {
389- self . status = Service . Status ( rawValue: statusString)
390- }
391- }
392-
393- // MARK: - Serialization -
394-
395- /// Serializes the object to the IPAPI format.
396- func toJSON( ) -> Service . JSON
397- {
398- var ret : Service . JSON = [ : ]
399-
400- ret [ Service . Field. `as`. rawValue] = self . `as` as AnyObject ?
401- ret [ Service . Field. city. rawValue] = self . city as AnyObject ?
402- ret [ Service . Field. countryCode. rawValue] = self . countryCode as AnyObject ?
403- ret [ Service . Field. countryName. rawValue] = self . countryName as AnyObject ?
404- ret [ Service . Field. ip. rawValue] = self . ip as AnyObject ?
405- ret [ Service . Field. isp. rawValue] = self . isp as AnyObject ?
406- ret [ Service . Field. latitude. rawValue] = self . latitude as AnyObject ?
407- ret [ Service . Field. longitude. rawValue] = self . longitude as AnyObject ?
408- ret [ Service . Field. message. rawValue] = self . message as AnyObject ?
409- ret [ Service . Field. mobile. rawValue] = self . mobile as AnyObject ?
410- ret [ Service . Field. organization. rawValue] = self . organization as AnyObject ?
411- ret [ Service . Field. proxy. rawValue] = self . proxy as AnyObject ?
412- ret [ Service . Field. regionCode. rawValue] = self . regionCode as AnyObject ?
413- ret [ Service . Field. regionName. rawValue] = self . regionName as AnyObject ?
414- ret [ Service . Field. reverse. rawValue] = self . reverse as AnyObject ?
415- ret [ Service . Field. status. rawValue] = self . status as AnyObject ?
416- ret [ Service . Field. timezone. rawValue] = self . timezone as AnyObject ?
417- ret [ Service . Field. zipCode. rawValue] = self . zipCode as AnyObject ?
418-
419- return ret
420- }
421-
422- }
423-
424313//
425314// # Request: JSON Extension
426315//
@@ -434,10 +323,8 @@ public extension Service.Request
434323 {
435324 /// Query.
436325 case query
437-
438326 /// Fields.
439327 case fields
440-
441328 /// Language.
442329 case language = " lang "
443330 }
@@ -458,7 +345,7 @@ public extension Service.Request
458345
459346 if let string = json [ Service . Request. JSONKey. fields. rawValue] as? String {
460347 let fields = string. components ( separatedBy: " , " )
461- self . fields = fields. flatMap { Service . Field ( rawValue: $0) }
348+ self . fields = fields. flatMap { Service . Result . Field ( rawValue: $0) }
462349 }
463350 } else {
464351 return nil
@@ -480,17 +367,3 @@ public extension Service.Request
480367 }
481368
482369}
483-
484- //
485- // # Debug Extension
486- //
487-
488- public extension Service . Result
489- {
490-
491- /// The textual representation of the receiver, in the form of JSON.
492- var description : String {
493- return self . toJSON ( ) . description
494- }
495-
496- }
0 commit comments