Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import Foundation
- struct Settings {
- static let shared = Settings()
- let apiHost = "[redacted]"
- let apiPath = "[redacted]"
- }
- // MARK: - Common endpoint handling
- enum Endpoint: String, CaseIterable {
- case locations
- case reportedquests
- // Other endpoints here
- var filename: String {
- return self.rawValue
- }
- var fullURL: URL {
- return URL(string: "\(Settings.shared.apiHost)\(Settings.shared.apiPath)\(filename)")!
- }
- }
- /// All endpoint responses must conform to this protocol
- protocol QTResponse: Decodable {
- associatedtype ResponseType: Codable
- var timestamp: Date { get }
- var error: String? { get }
- var result: ResponseType? { get }
- }
- // MARK: - Endpoint definitions
- struct LocationsResponse: QTResponse {
- let timestamp: Date
- let error: String?
- let result: [Location]?
- }
- enum LocationType: String, Codable {
- case stop
- case gym
- }
- struct Location: Codable {
- let identifier: String
- let name: String
- let type: LocationType
- let latitude: Double
- let longitude: Double
- }
- struct ReportedQuestsResponse: QTResponse {
- let timestamp: Date
- let error: String?
- let result: [ReportedQuest]?
- }
- struct ReportedQuest: Codable {
- let location: String
- let rewardType: String
- let rewardDetails: String?
- let task: String?
- let reportedBy: String
- }
- // MARK: - Custom JSON decoder
- class CustomJSONDecoder: JSONDecoder {
- enum JSONError: Error {
- case noResultError
- case serverError(text: String)
- }
- override init() {
- super.init()
- self.dateDecodingStrategy = .formatted(DateFormatter.iso8601Full)
- }
- override func decode<T>(_ type: T.Type, from data: Data) throws -> T where T: QTResponse {
- let decoded = try super.decode(type, from: data)
- guard decoded.error == nil else { throw JSONError.serverError(text: decoded.error!) }
- guard decoded.result != nil else { throw JSONError.noResultError }
- return decoded
- }
- }
- extension DateFormatter {
- static let iso8601Full: DateFormatter = {
- let formatter = DateFormatter()
- formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
- formatter.calendar = Calendar(identifier: .iso8601)
- formatter.timeZone = TimeZone(secondsFromGMT: 0)
- formatter.locale = Locale(identifier: "en_US_POSIX")
- return formatter
- }()
- }
- // MARK: - RequestHelper
- class RequestHandler {
- enum RequestError: Error {
- case notHttpResponse
- case noData
- case parseError
- }
- static func get(_ url: URL, callback: @escaping (Error?, Data?, Int?) -> Void) {
- var request = URLRequest(url: url)
- request.httpMethod = "GET"
- // Add some custom headers here
- let task = URLSession.shared.dataTask(with: request) { (data, res, err) in
- DispatchQueue.main.async {
- guard err == nil else { return callback(err, nil, nil) }
- guard let httpResponse = res as? HTTPURLResponse
- else { return callback(RequestHandler.RequestError.notHttpResponse, nil, nil) }
- guard let responseData = data else { return callback(RequestHandler.RequestError.noData, nil, httpResponse.statusCode) }
- callback(nil, responseData, httpResponse.statusCode)
- }
- }
- task.resume()
- }
- }
- // MARK: - DataLoader
- class DataLoader {
- static let shared = DataLoader()
- func loadAll() {
- let decoder = CustomJSONDecoder()
- Endpoint.allCases.forEach { endpoint in
- RequestHandler.get(endpoint.fullURL) { (error, data, statusCode) in
- guard error == nil else { print("Request error: \(error!.localizedDescription)"); return }
- guard let data = data else { print("No data returned from server"); return }
- do {
- switch endpoint {
- case .locations:
- let response = try decoder.decode(LocationsResponse.self, from: data)
- response.result?.forEach { print($0.name) }
- case.reportedquests:
- let response = try decoder.decode(ReportedQuestsResponse.self, from: data)
- response.result?.forEach { print($0.rewardType) }
- }
- } catch CustomJSONDecoder.JSONError.noResultError {
- print("Result object was nil")
- } catch CustomJSONDecoder.JSONError.serverError(let text) {
- print("Server returned error message: \(text)")
- } catch {
- print("JSON decoding error: \(error.localizedDescription)")
- }
- }
- }
- }
- }
- DataLoader.shared.loadAll()
Add Comment
Please, Sign In to add comment