diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ac41b0b..50f44e39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ # Changelog +### 0.9.4 +- **Add**: initialization of `ApiRequestParameters`, that takes an array as a request parameter. +- **Add**: `NetworkServiceConfiguration.apiRequestParameters` method, that creates `ApiRequestParameters` with array request parameter. +- **Add**: `SessionManager.request` method, that takes an array as a request parameter. +- **Add**: `RequestUsageError` error, that represents wrong usage of requset parameters. + ### 0.9.3 - **Add**: `Insert`/`Remove` section with animation functions to `TableKit`. Also make new function `Replace` that uses new `Insert`/`Remove` to animate section replace. diff --git a/LeadKit.podspec b/LeadKit.podspec index f0a18701..5aa0ebbc 100644 --- a/LeadKit.podspec +++ b/LeadKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "LeadKit" - s.version = "0.9.3" + s.version = "0.9.4" s.summary = "iOS framework with a bunch of tools for rapid development" s.homepage = "https://github.com/TouchInstinct/LeadKit" s.license = "Apache License, Version 2.0" diff --git a/Sources/Extensions/Alamofire/SessionManager+Extensions.swift b/Sources/Extensions/Alamofire/SessionManager+Extensions.swift index fcc1d52b..94e39703 100644 --- a/Sources/Extensions/Alamofire/SessionManager+Extensions.swift +++ b/Sources/Extensions/Alamofire/SessionManager+Extensions.swift @@ -24,20 +24,86 @@ import Alamofire import RxSwift import RxAlamofire +/// Enum that represents wrong usage of requset parameters +/// +/// - getMethodForbidden: invalid usage of get method +/// - urlEncodingForbidden: invalid usage of URLEncoding +enum RequestUsageError: Error { + + case getMethodForbidden + case urlEncodingForbidden + +} + public extension Reactive where Base: SessionManager { + + /// Creates an observable of the `Request`. + /// + /// - Parameters: + /// - method: Alamofire method object + /// - url: An object adopting `URLConvertible` + /// - parameters: An array of JSON objects containing all necessary options + /// - encoding: The kind of encoding used to process parameters + /// - headers: A dictionary containing all the additional headers + /// - Returns: An observable of the `Request` + public func request(_ method: Alamofire.HTTPMethod, + _ url: URLConvertible, + parameters: [Any]? = nil, + encoding: JSONEncoding = .default, + headers: [String: String]? = nil) + -> Observable { + + return Observable.deferred { + + guard method != .get else { + assertionFailure("Unable to pass array in get request") + throw RequestUsageError.getMethodForbidden + } + + let urlRequest = try URLRequest(url: try url.asURL(), method: method, headers: headers) + let encodedUrlRequest = try encoding.encode(urlRequest, withJSONObject: parameters) + + return self.request(urlRequest: encodedUrlRequest) + } + } + /// Method which executes request with given api parameters /// /// - Parameter requestParameters: api parameters to pass Alamofire /// - Returns: Observable with request func apiRequest(requestParameters: ApiRequestParameters) -> Observable { - - return request(requestParameters.method, - requestParameters.url, - parameters: requestParameters.parameters, - encoding: requestParameters.encoding, - headers: requestParameters.headers) + + let requestObservable: Observable + + switch requestParameters.parameters { + case .dictionary(let parameters)?: + requestObservable = request(requestParameters.method, + requestParameters.url, + parameters: parameters, + encoding: requestParameters.encoding, + headers: requestParameters.headers) + case .array(let parameters)?: + guard let encoding = requestParameters.encoding as? JSONEncoding else { + assertionFailure("Invalid encoding type with array parameter") + return .error(RequestUsageError.urlEncodingForbidden) + } + + requestObservable = request(requestParameters.method, + requestParameters.url, + parameters: parameters, + encoding: encoding, + headers: requestParameters.headers) + case .none: + requestObservable = request(requestParameters.method, + requestParameters.url, + parameters: nil as Parameters?, + encoding: requestParameters.encoding, + headers: requestParameters.headers) + } + + return requestObservable .map { $0.validate(statusCode: self.base.acceptableStatusCodes) } } diff --git a/Sources/Structures/Api/ApiRequestParameters.swift b/Sources/Structures/Api/ApiRequestParameters.swift index c9ccafd0..411ff4e8 100644 --- a/Sources/Structures/Api/ApiRequestParameters.swift +++ b/Sources/Structures/Api/ApiRequestParameters.swift @@ -27,9 +27,18 @@ import Alamofire */ public struct ApiRequestParameters { + /// Enum which keeps parameters type for request body + /// + /// - dictionary: dictionary parameter + /// - array: array parameter + enum RequestParameters { + case dictionary(Parameters) + case array([Any]) + } + let method: HTTPMethod let url: URLConvertible - let parameters: Parameters? + let parameters: RequestParameters? let encoding: ParameterEncoding let headers: HTTPHeaders? @@ -41,9 +50,30 @@ public struct ApiRequestParameters { self.method = method self.url = url - self.parameters = parameters self.encoding = encoding self.headers = headers + if let parameters = parameters { + self.parameters = .dictionary(parameters) + } else { + self.parameters = nil + } + } + + public init(url: URLConvertible, + method: HTTPMethod = .get, + parameters: [Any]? = nil, + encoding: ParameterEncoding = URLEncoding.default, + headers: HTTPHeaders? = nil) { + + self.method = method + self.url = url + self.encoding = encoding + self.headers = headers + if let parameters = parameters { + self.parameters = .array(parameters) + } else { + self.parameters = nil + } } } diff --git a/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift b/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift index 494072d6..231dd924 100644 --- a/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift +++ b/Sources/Structures/NetworkService/NetworkServiceConfiguration.swift @@ -95,5 +95,26 @@ public extension NetworkServiceConfiguration { encoding: requestEncoding ?? encoding, headers: requestHeaders) } + + /// Convenient method to create ApiRequestParameters. + /// + /// - Parameters: + /// - relativeUrl: Url that will be concatenated with base url. + /// - method: HTTP method to use for request. + /// - parameters: An array of JSON objects to apply to a URLRequest. + /// - requestEncoding: Encoding type to use. If passed nil, configuration encoding will be used. + /// - requestHeaders: Dictionary of headers to apply to a URLRequest. + /// - Returns: Initialized instance of ApiRequestParameters with given parameters. + func apiRequestParameters(relativeUrl: String, + method: HTTPMethod = .get, + parameters: [Any]? = nil, + requestEncoding: ParameterEncoding? = nil, + requestHeaders: HTTPHeaders? = nil) -> ApiRequestParameters { + return ApiRequestParameters(url: baseUrl + relativeUrl, + method: method, + parameters: parameters, + encoding: requestEncoding ?? encoding, + headers: requestHeaders) + } }