From 8d6a2bd09634e6885a213cfb75a44e2c5f6feafd Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Wed, 16 Sep 2020 22:26:04 +0300 Subject: Initial API service in Swift # Conflicts: # Juick.xcodeproj/project.pbxproj --- Juick/Service.swift | 135 +++++++++++++++++++++++++ Juick/Supporting Files/Juick-Bridging-Header.h | 3 + 2 files changed, 138 insertions(+) create mode 100644 Juick/Service.swift create mode 100644 Juick/Supporting Files/Juick-Bridging-Header.h (limited to 'Juick') diff --git a/Juick/Service.swift b/Juick/Service.swift new file mode 100644 index 0000000..441451e --- /dev/null +++ b/Juick/Service.swift @@ -0,0 +1,135 @@ +// +// Service.swift +// Juick +// +// Created by Vitaly Takmazov on 16.09.2020. +// Copyright © 2020 com.juick. All rights reserved. +// + +import Foundation + +class Service : NSObject, URLSessionDelegate, URLSessionTaskDelegate { + let backgroundQueue = OperationQueue() + + let baseURL : URL? + + lazy var authorizationHeader : String? = { + if let token = UserDefaults.standard.string(forKey: "token") { + return "Juick \(token)" + } + return nil; + }() + + override init() { + let baseURLString = Bundle.main.object(forInfoDictionaryKey:"base_url") as! String + debugPrint("Initializing with \(baseURLString) base URL") + self.baseURL = URL(string: baseURLString) + super.init() + } + func url(url:URL, params:[String: String]) -> URL { + let parametersUrl = NSURLComponents(url: url, resolvingAgainstBaseURL: true) + var items : [URLQueryItem] = [] + for (key, value) in params { + items.append(URLQueryItem(name: key, value: value)) + } + parametersUrl?.queryItems = items + return (parametersUrl?.url!)! + } + func fetchData(url:URL, postData:Data?, boundary:String?, header:String?, callback: @escaping (Data?, Error?) -> Void) { + var request = URLRequest(url: url) + if (header != nil) { + request.addValue(header!, forHTTPHeaderField:"Authorization") + } + if (boundary != nil) { + request.httpMethod = "POST"; + request.httpBody = postData; + let contentType = "multipart/form-data; boundary=\(boundary!)" + request.setValue(contentType, forHTTPHeaderField:"Content-Type") + } else if (postData != nil) { + request.httpMethod = "PUT"; + request.httpBody = postData; + request.setValue("application/json", forHTTPHeaderField:"Content-Type") + } else { + request.httpMethod = "GET"; + } + + let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in + if (error != nil) { + OperationQueue.main.addOperation { + callback(nil, error) + } + } else { + let statusCode = (response as? HTTPURLResponse)?.statusCode ?? 457 + if (response == nil || statusCode != 200) { + let url = request.url + let err = NSError(domain: "JuickErrorDomain", code: statusCode, userInfo: ["url":url!.absoluteString]) + OperationQueue.main.addOperation { + callback(nil, err) + } + } else { + OperationQueue.main.addOperation { + callback(data, error) + } + } + } + }) + self.backgroundQueue.addOperation { + task.resume() + } + } + private func multipartData(params:[String:String], boundary:String) -> Data { + var body = Data() + for (key, value) in params { + body.append("--\(boundary)\r\n".data(using: .utf8)!) + body.append("Content-Disposition: form-data; name=\(key)\r\n\r\n".data(using: .utf8)!) + body.append("\(value)\r\n".data(using: .utf8)!) + } + body.append("--\(boundary)--".data(using: .utf8)!) + return body; + } + private func get(path:String, params:[String:String], callback:@escaping (NSDictionary?, Error?) -> Void) { + if let url = URL(string: path, relativeTo: self.baseURL) { + let requestUrl = params.isEmpty ? url : self.url(url: url, params: params) + fetchData(url: requestUrl, postData: nil, boundary: nil, header: self.authorizationHeader) { + (responseData, err) in + if (err != nil) { + callback(nil, err) + } else { + if let data = responseData, let jsonData = try? JSONSerialization.jsonObject(with: data, options: []) { + callback(jsonData as? NSDictionary, nil) + } else { + callback(nil, NSError(domain: "JuickErrorDomain", code: 500, userInfo: ["message":"JSON error"])) + } + } + } + } + } + + func post(path: String, params:[String:String], callback:@escaping (NSDictionary?, Error?) -> Void) { + if let url = URL(string: path, relativeTo: self.baseURL) { + let boundary = "Boundary-\(UUID().uuidString)"; + fetchData(url: url, postData:multipartData(params: params, boundary: boundary), boundary: boundary, header: self.authorizationHeader) { + (responseData, err) in + if (err != nil) { + callback(nil, err) + } else { + if let data = responseData, let jsonData = try? JSONSerialization.jsonObject(with: data, options: []) { + callback(jsonData as? NSDictionary, nil) + } else { + callback(nil, NSError(domain: "JuickErrorDomain", code: 500, userInfo: ["message":"JSON error"])) + } + } + } + } + } + + func fetchImage(url:URL, callback:@escaping(Data?)-> Void) { + fetchData(url: url, postData: nil, boundary: nil, header: self.authorizationHeader) { (data, err) in + if (err != nil) { + callback(nil); + } else { + callback(data); + } + } + } +} diff --git a/Juick/Supporting Files/Juick-Bridging-Header.h b/Juick/Supporting Files/Juick-Bridging-Header.h new file mode 100644 index 0000000..e11d920 --- /dev/null +++ b/Juick/Supporting Files/Juick-Bridging-Header.h @@ -0,0 +1,3 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// -- cgit v1.2.3