From fb0e1090e5cbd12cee146d2d54c792a425f114a0 Mon Sep 17 00:00:00 2001 From: Ivan Smolin Date: Thu, 1 Jul 2021 22:30:41 +0300 Subject: [PATCH 01/11] add TINetworking --- Package.resolved | 9 +++ Package.swift | 9 ++- .../ApplicationJsonBodyContent.swift | 25 ++++++++ .../Mapping/BodyContent/BodyContent.swift | 5 ++ .../BodyContent/EmptyBodyContent.swift | 13 ++++ .../Sources/Mapping/Codable+Required.swift | 21 +++++++ TINetworking/Sources/Mapping/Content.swift | 3 + TINetworking/Sources/Mapping/MediaType.swift | 4 ++ .../Mapping/OneOfMapping/AnyTypeMapping.swift | 22 +++++++ .../OneOfMapping/OneOfMappingError.swift | 21 +++++++ .../ApplicationJsonResponseContent.swift | 17 ++++++ .../ResponseContent/MapResponseContent.swift | 18 ++++++ .../ResponseContent/ResponseContent.swift | 7 +++ .../TextPlainResponseContent.swift | 24 ++++++++ .../Encoding/BaseUrlParameterEncoding.swift | 30 ++++++++++ .../Encoding/HeadersParameterEncoding.swift | 13 ++++ .../Encoding/PathParameterEncoding.swift | 11 ++++ .../QueryStringParameterEncoding.swift | 9 +++ .../Sources/Parameters/Parameter.swift | 9 +++ .../Parameters/ParameterEncoding.swift | 6 ++ .../Parameters/ParameterLocation.swift | 6 ++ TINetworking/Sources/Request/Request.swift | 42 +++++++++++++ .../Response/MimeTypeUnsupportedError.swift | 12 ++++ .../Response/ResponseType+Decoding.swift | 45 ++++++++++++++ .../Sources/Response/ResponseType.swift | 14 +++++ ...atusCodeMimeTypePairUnsupportedError.swift | 14 +++++ TINetworking/Sources/Server.swift | 59 +++++++++++++++++++ TINetworking/Sources/SessionFactory.swift | 37 ++++++++++++ .../Sources/String+URLExtensions.swift | 17 ++++++ TINetworking/Sources/Typealiases.swift | 1 + 30 files changed, 520 insertions(+), 3 deletions(-) create mode 100644 TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift create mode 100644 TINetworking/Sources/Mapping/BodyContent/BodyContent.swift create mode 100644 TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift create mode 100644 TINetworking/Sources/Mapping/Codable+Required.swift create mode 100644 TINetworking/Sources/Mapping/Content.swift create mode 100644 TINetworking/Sources/Mapping/MediaType.swift create mode 100644 TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift create mode 100644 TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift create mode 100644 TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift create mode 100644 TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift create mode 100644 TINetworking/Sources/Mapping/ResponseContent/ResponseContent.swift create mode 100644 TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift create mode 100644 TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift create mode 100644 TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift create mode 100644 TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift create mode 100644 TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift create mode 100644 TINetworking/Sources/Parameters/Parameter.swift create mode 100644 TINetworking/Sources/Parameters/ParameterEncoding.swift create mode 100644 TINetworking/Sources/Parameters/ParameterLocation.swift create mode 100644 TINetworking/Sources/Request/Request.swift create mode 100644 TINetworking/Sources/Response/MimeTypeUnsupportedError.swift create mode 100644 TINetworking/Sources/Response/ResponseType+Decoding.swift create mode 100644 TINetworking/Sources/Response/ResponseType.swift create mode 100644 TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift create mode 100644 TINetworking/Sources/Server.swift create mode 100644 TINetworking/Sources/SessionFactory.swift create mode 100644 TINetworking/Sources/String+URLExtensions.swift create mode 100644 TINetworking/Sources/Typealiases.swift diff --git a/Package.resolved b/Package.resolved index 3dfc4c9c..94b92e20 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,6 +1,15 @@ { "object": { "pins": [ + { + "package": "Alamofire", + "repositoryURL": "https://github.com/Alamofire/Alamofire.git", + "state": { + "branch": null, + "revision": "f96b619bcb2383b43d898402283924b80e2c4bae", + "version": "5.4.3" + } + }, { "package": "Cursors", "repositoryURL": "https://github.com/petropavel13/Cursors", diff --git a/Package.swift b/Package.swift index cc2dca77..f4763d53 100644 --- a/Package.swift +++ b/Package.swift @@ -17,6 +17,7 @@ let package = Package( .library(name: "TIFoundationUtils", targets: ["TIFoundationUtils"]), .library(name: "TIKeychainUtils", targets: ["TIKeychainUtils"]), .library(name: "TITableKitUtils", targets: ["TITableKitUtils"]), + .library(name: "TINetworking", targets: ["TINetworking"]), // MARK: - Elements .library(name: "OTPSwiftView", targets: ["OTPSwiftView"]), @@ -24,9 +25,10 @@ let package = Package( .library(name: "TIPagination", targets: ["TIPagination"]), ], dependencies: [ - .package(url: "https://github.com/maxsokolov/TableKit.git", from: "2.11.0"), - .package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", from: "4.2.2"), - .package(url: "https://github.com/petropavel13/Cursors", from: "0.5.1") + .package(url: "https://github.com/maxsokolov/TableKit.git", .upToNextMajor(from: "2.11.0")), + .package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", .upToNextMajor(from: "4.2.2")), + .package(url: "https://github.com/petropavel13/Cursors", .upToNextMajor(from: "0.5.1")), + .package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.4.0")), ], targets: [ @@ -39,6 +41,7 @@ let package = Package( .target(name: "TIFoundationUtils", dependencies: ["TISwiftUtils"], path: "TIFoundationUtils/Sources"), .target(name: "TIKeychainUtils", dependencies: ["TIFoundationUtils", "KeychainAccess"], path: "TIKeychainUtils/Sources"), .target(name: "TITableKitUtils", dependencies: ["TIUIElements", "TableKit"], path: "TITableKitUtils/Sources"), + .target(name: "TINetworking", dependencies: ["Alamofire"], path: "TINetworking/Sources"), // MARK: - Elements diff --git a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift new file mode 100644 index 00000000..316b3113 --- /dev/null +++ b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift @@ -0,0 +1,25 @@ +import Foundation + +open class ApplicationJsonBodyContent: BodyContent { + public var mediaTypeName: String { + MediaType.applicationJson.rawValue + } + + private let encodingClosure: () throws -> Data + + public init(body: Body, jsonEncoder: JSONEncoder = JSONEncoder()) where Body: Encodable { + self.encodingClosure = { + try jsonEncoder.encode(body) + } + } + + public init(jsonBody: Body, options: JSONSerialization.WritingOptions = .prettyPrinted) { + self.encodingClosure = { + try JSONSerialization.data(withJSONObject: jsonBody, options: options) + } + } + + public func encodeBody() throws -> Data { + try encodingClosure() + } +} diff --git a/TINetworking/Sources/Mapping/BodyContent/BodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/BodyContent.swift new file mode 100644 index 00000000..58093c6c --- /dev/null +++ b/TINetworking/Sources/Mapping/BodyContent/BodyContent.swift @@ -0,0 +1,5 @@ +import Foundation + +public protocol BodyContent: Content { + func encodeBody() throws -> Data +} diff --git a/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift new file mode 100644 index 00000000..12d1579f --- /dev/null +++ b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift @@ -0,0 +1,13 @@ +import Foundation + +public struct EmptyBodyContent: BodyContent { + public var mediaTypeName: String { + MediaType.textPlain.rawValue + } + + public init() {} + + public func encodeBody() throws -> Data { + Data() + } +} diff --git a/TINetworking/Sources/Mapping/Codable+Required.swift b/TINetworking/Sources/Mapping/Codable+Required.swift new file mode 100644 index 00000000..8cceb3b6 --- /dev/null +++ b/TINetworking/Sources/Mapping/Codable+Required.swift @@ -0,0 +1,21 @@ +public extension KeyedDecodingContainer { + func decode(_ type: T?.Type, + forKey key: Key, + required: Bool) throws -> T? { + + required ? try decode(type, forKey: key) : try decodeIfPresent(T.self, forKey: key) + } +} + +public extension KeyedEncodingContainer { + mutating func encode(_ value: T?, + forKey key: Key, + required: Bool) throws { + + if let value = value { + try encode(value, forKey: key) + } else if required { + try encodeNil(forKey: key) + } + } +} diff --git a/TINetworking/Sources/Mapping/Content.swift b/TINetworking/Sources/Mapping/Content.swift new file mode 100644 index 00000000..41b26a9b --- /dev/null +++ b/TINetworking/Sources/Mapping/Content.swift @@ -0,0 +1,3 @@ +public protocol Content { + var mediaTypeName: String { get } +} diff --git a/TINetworking/Sources/Mapping/MediaType.swift b/TINetworking/Sources/Mapping/MediaType.swift new file mode 100644 index 00000000..387a36f1 --- /dev/null +++ b/TINetworking/Sources/Mapping/MediaType.swift @@ -0,0 +1,4 @@ +public enum MediaType: String { + case applicationJson = "application/json" + case textPlain = "text/plain" +} diff --git a/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift b/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift new file mode 100644 index 00000000..b1b97cb2 --- /dev/null +++ b/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift @@ -0,0 +1,22 @@ +public struct AnyTypeMapping { + public let type: Any.Type + private let mappingClosure: () -> Result + + public init(decoder: Decoder, + transform: @escaping (T) -> R) { + + type = T.self + + mappingClosure = { + do { + return .success(transform(try T(from: decoder))) + } catch { + return .failure(error) + } + } + } + + public func decode() -> Result { + mappingClosure() + } +} diff --git a/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift b/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift new file mode 100644 index 00000000..c7c025b8 --- /dev/null +++ b/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift @@ -0,0 +1,21 @@ +public struct OneOfMappingError: Error, CustomDebugStringConvertible { + public typealias MappingFailures = [KeyValueTuple] + + public let codingPath: [CodingKey] + public let mappingFailures: MappingFailures + + public init(codingPath: [CodingKey], mappingFailures: MappingFailures) { + self.codingPath = codingPath + self.mappingFailures = mappingFailures + } + + public var debugDescription: String { + var formattedString = "OneOf mapping failed for codingPath \(codingPath)\nwith following errors:\n" + + for (type, error) in mappingFailures { + formattedString += "\(type) mapping failed with error: \(error)\n" + } + + return formattedString + } +} diff --git a/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift new file mode 100644 index 00000000..498ea08b --- /dev/null +++ b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift @@ -0,0 +1,17 @@ +import Foundation + +open class ApplicationJsonResponseContent: ResponseContent { + public var mediaTypeName: String { + MediaType.applicationJson.rawValue + } + + public let jsonDecoder: JSONDecoder + + public init(jsonDecoder: JSONDecoder = JSONDecoder()) { + self.jsonDecoder = jsonDecoder + } + + public func decodeResponse(data: Data) throws -> Model { + try jsonDecoder.decode(Model.self, from: data) + } +} diff --git a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift new file mode 100644 index 00000000..ebcca1c0 --- /dev/null +++ b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift @@ -0,0 +1,18 @@ +import Foundation + +public struct MapResponseContent: ResponseContent { + public let mediaTypeName: String + + private let decodeClosure: (Data) throws -> Model + + public init(responseContent: C, transform: @escaping (C.Model) -> Model) { + self.mediaTypeName = responseContent.mediaTypeName + self.decodeClosure = { + transform(try responseContent.decodeResponse(data: $0)) + } + } + + public func decodeResponse(data: Data) throws -> Model { + try decodeClosure(data) + } +} diff --git a/TINetworking/Sources/Mapping/ResponseContent/ResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/ResponseContent.swift new file mode 100644 index 00000000..3d600f79 --- /dev/null +++ b/TINetworking/Sources/Mapping/ResponseContent/ResponseContent.swift @@ -0,0 +1,7 @@ +import Foundation + +public protocol ResponseContent: Content { + associatedtype Model + + func decodeResponse(data: Data) throws -> Model +} diff --git a/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift new file mode 100644 index 00000000..ebfa6c73 --- /dev/null +++ b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift @@ -0,0 +1,24 @@ +import Foundation + +public struct TextPlainResponseContent: ResponseContent { + struct UnableToDecodeStringError: Error { + let data: Data + let encoding: String.Encoding + } + + private let encoding: String.Encoding + + public init(encoding: String.Encoding = .utf8) { + self.encoding = encoding + } + + public let mediaTypeName = MediaType.textPlain.rawValue + + public func decodeResponse(data: Data) throws -> String { + guard let plainText = String(data: data, encoding: encoding) else { + throw UnableToDecodeStringError(data: data, encoding: encoding) + } + + return plainText + } +} diff --git a/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift new file mode 100644 index 00000000..85b1c119 --- /dev/null +++ b/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift @@ -0,0 +1,30 @@ +import Alamofire + +open class BaseUrlParameterEncoding { + private let encoding: URLEncoding = .queryString + + public init() { + } + + open func encode(parameters: [String: Parameter]) -> [KeyValueTuple] { + var filteredComponents: [(String, String)] = [] + + for key in parameters.keys.sorted(by: <) { + guard let parameter = parameters[key] else { + continue + } + + let components: [KeyValueTuple] = encoding.queryComponents(fromKey: key, value: parameter.value) + + for component in components { + if component.value.isEmpty && !parameter.allowEmptyValue { + continue + } + + filteredComponents.append(component) + } + } + + return filteredComponents + } +} diff --git a/TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift new file mode 100644 index 00000000..7c4f058a --- /dev/null +++ b/TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift @@ -0,0 +1,13 @@ +open class HeadersParameterEncoding: BaseUrlParameterEncoding, ParameterEncoding { + public let sequenceSeparator: String + + public init(sequenceSeparator: String = ";") { + self.sequenceSeparator = sequenceSeparator + } + + open func encode(parameters: [String: Parameter]) -> [String: String] { + Dictionary(encode(parameters: parameters)) { + $0 + sequenceSeparator + $1 + } + } +} diff --git a/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift new file mode 100644 index 00000000..f9501c5f --- /dev/null +++ b/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift @@ -0,0 +1,11 @@ +open class PathParameterEncoding: BaseUrlParameterEncoding, ParameterEncoding { + public let templateUrl: String + + public init(templateUrl: String) { + self.templateUrl = templateUrl + } + + open func encode(parameters: [String: Parameter]) -> String { + .render(template: templateUrl, using: encode(parameters: parameters)) + } +} diff --git a/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift new file mode 100644 index 00000000..bef188bb --- /dev/null +++ b/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift @@ -0,0 +1,9 @@ +open class QueryStringParameterEncoding: BaseUrlParameterEncoding, ParameterEncoding { + open func encode(parameters: [String: Parameter]) -> [String: Any] { + let includedKeys = Set(super.encode(parameters: parameters).map { $0.key }) + + return parameters + .filter { includedKeys.contains($0.key) } + .mapValues { $0.value } + } +} diff --git a/TINetworking/Sources/Parameters/Parameter.swift b/TINetworking/Sources/Parameters/Parameter.swift new file mode 100644 index 00000000..5158c7dd --- /dev/null +++ b/TINetworking/Sources/Parameters/Parameter.swift @@ -0,0 +1,9 @@ +public struct Parameter { + public let value: Any + public let allowEmptyValue: Bool + + public init(value: Any, allowEmptyValue: Bool = false) { + self.value = value + self.allowEmptyValue = allowEmptyValue + } +} diff --git a/TINetworking/Sources/Parameters/ParameterEncoding.swift b/TINetworking/Sources/Parameters/ParameterEncoding.swift new file mode 100644 index 00000000..ff1b362c --- /dev/null +++ b/TINetworking/Sources/Parameters/ParameterEncoding.swift @@ -0,0 +1,6 @@ +protocol ParameterEncoding { + associatedtype Location: ParameterLocation + associatedtype Result + + func encode(parameters: [String: Parameter]) -> Result +} diff --git a/TINetworking/Sources/Parameters/ParameterLocation.swift b/TINetworking/Sources/Parameters/ParameterLocation.swift new file mode 100644 index 00000000..92e0d943 --- /dev/null +++ b/TINetworking/Sources/Parameters/ParameterLocation.swift @@ -0,0 +1,6 @@ +public protocol ParameterLocation {} + +public struct LocationQuery: ParameterLocation {} +public struct LocationPath: ParameterLocation {} +public struct LocationHeader: ParameterLocation {} +public struct LocationCookie: ParameterLocation {} diff --git a/TINetworking/Sources/Request/Request.swift b/TINetworking/Sources/Request/Request.swift new file mode 100644 index 00000000..3505e96e --- /dev/null +++ b/TINetworking/Sources/Request/Request.swift @@ -0,0 +1,42 @@ +import Alamofire + +public struct Request { + + public var templatePath: String + public var method: HTTPMethod + public var requestBodyContent: Content + public var queryParameters: [String: Parameter] + public var pathParameters: [String: Parameter] + public var headerParameters: [String: Parameter] + public var cookieParameters: [String: Parameter] + public var acceptableStatusCodes: Set + public var serverOverride: Server? + public var serverVariablesOverride: [KeyValueTuple] + + public var path: String { + PathParameterEncoding(templateUrl: templatePath).encode(parameters: pathParameters) + } + + public init(templatePath: String, + method: HTTPMethod, + requestBodyContent: Content, + queryParameters: [String: Parameter] = [:], + pathParameters: [String: Parameter] = [:], + headerParameters: [String: Parameter] = [:], + cookieParameters: [String: Parameter] = [:], + acceptableStatusCodes: Set = [200], + serverOverride: Server? = nil, + serverVariablesOverride: [KeyValueTuple] = []) { + + self.templatePath = templatePath + self.method = method + self.requestBodyContent = requestBodyContent + self.queryParameters = queryParameters + self.pathParameters = pathParameters + self.headerParameters = headerParameters + self.cookieParameters = cookieParameters + self.acceptableStatusCodes = acceptableStatusCodes + self.serverOverride = serverOverride + self.serverVariablesOverride = serverVariablesOverride + } +} diff --git a/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift b/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift new file mode 100644 index 00000000..8a885b58 --- /dev/null +++ b/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift @@ -0,0 +1,12 @@ +open class MimeTypeUnsupportedError: Error, CustomDebugStringConvertible { + + public let mimeType: String? + + public init(mimeType: String?) { + self.mimeType = mimeType + } + + public var debugDescription: String { + "Mime type \(mimeType.debugDescription) isn't supported." + } +} diff --git a/TINetworking/Sources/Response/ResponseType+Decoding.swift b/TINetworking/Sources/Response/ResponseType+Decoding.swift new file mode 100644 index 00000000..e1f475a5 --- /dev/null +++ b/TINetworking/Sources/Response/ResponseType+Decoding.swift @@ -0,0 +1,45 @@ +public struct ResponseTypeDecodingError: Error { + public let statusCode: Int + public let contentType: String +} + +public struct ContentMapping { + public let statusCode: Int + public let mimeType: String? + public let responseContent: Content + + public init(statusCode: Int, mimeType: String?, responseContent: Content) { + self.statusCode = statusCode + self.mimeType = mimeType + self.responseContent = responseContent + } + + public func map(transform: @escaping (Content.Model) -> NewModel) -> ContentMapping> { + .init(statusCode: statusCode, + mimeType: mimeType, + responseContent: MapResponseContent(responseContent: responseContent, + transform: transform)) + } +} + +public extension ResponseType { + func decode(contentMapping: [ContentMapping]) -> Result { + for mapping in contentMapping where mapping.statusCode == statusCode && mapping.mimeType == mimeType { + do { + return .success(try mapping.responseContent.decodeResponse(data: data)) + } catch { + return .failure(objectMappingError(underlyingError: error)) + } + } + + guard contentMapping.contains(where: { $0.statusCode == statusCode }) else { + return .failure(unsupportedStatusCodeError(statusCode: statusCode)) + } + + guard contentMapping.contains(where: { $0.mimeType == mimeType }) else { + return .failure(unsupportedMimeTypeError(mimeType: mimeType)) + } + + return .failure(unsupportedStatusCodeMimeTypePairError(statusCode: statusCode, mimeType: mimeType)) + } +} diff --git a/TINetworking/Sources/Response/ResponseType.swift b/TINetworking/Sources/Response/ResponseType.swift new file mode 100644 index 00000000..0e45359c --- /dev/null +++ b/TINetworking/Sources/Response/ResponseType.swift @@ -0,0 +1,14 @@ +import Foundation + +public protocol ResponseType { + associatedtype ErrorType: Error + + var statusCode: Int { get } + var data: Data { get } + var mimeType: String? { get } + + func unsupportedStatusCodeError(statusCode: Int) -> ErrorType + func unsupportedMimeTypeError(mimeType: String?) -> ErrorType + func objectMappingError(underlyingError: Error) -> ErrorType + func unsupportedStatusCodeMimeTypePairError(statusCode: Int, mimeType: String?) -> ErrorType +} diff --git a/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift b/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift new file mode 100644 index 00000000..909c20a9 --- /dev/null +++ b/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift @@ -0,0 +1,14 @@ +open class StatusCodeMimeTypePairUnsupportedError: MimeTypeUnsupportedError { + + public let statusCode: Int + + public init(statusCode: Int, mimeType: String?) { + self.statusCode = statusCode + + super.init(mimeType: mimeType) + } + + public override var debugDescription: String { + "Status code: \(statusCode), mimeType: \(mimeType ?? "nil") pair is unsupported!" + } +} diff --git a/TINetworking/Sources/Server.swift b/TINetworking/Sources/Server.swift new file mode 100644 index 00000000..2d3a11c3 --- /dev/null +++ b/TINetworking/Sources/Server.swift @@ -0,0 +1,59 @@ +import Foundation + +private enum Scheme: String { + case https + + var urlPrefix: String { + rawValue + "://" + } +} + +public struct Server { + public struct Variable { + public let values: [String] + public let defaultValue: String + + public init(values: [String], defaultValue: String) { + self.values = values + self.defaultValue = defaultValue + } + } + + public let urlTemplate: String + public let variables: [String: Variable] + + public init(urlTemplate: String, variables: [String: Variable]) { + self.urlTemplate = urlTemplate + self.variables = variables + } + + public init(baseUrl: String) { + self.init(urlTemplate: baseUrl, variables: [:]) + } + + private var defaultVariables: [KeyValueTuple] { + variables.map { ($0.key, $0.value.defaultValue) } + } + + public func url(using variables: [KeyValueTuple] = [], + appendHttpsSchemeIfMissing: Bool = true) -> URL? { + + guard !variables.isEmpty else { + return URL(string: .render(template: urlTemplate, using: defaultVariables)) + } + + let defaultVariablesToApply = self.defaultVariables + .filter { (key, _) in variables.contains { $0.key == key } } + + let defaultParametersTemplate = String.render(template: urlTemplate, + using: defaultVariablesToApply) + + let formattedUrlString = String.render(template: defaultParametersTemplate, using: variables) + + if appendHttpsSchemeIfMissing, !formattedUrlString.contains(Scheme.https.urlPrefix) { + return URL(string: Scheme.https.urlPrefix + formattedUrlString) + } + + return URL(string: formattedUrlString) + } +} diff --git a/TINetworking/Sources/SessionFactory.swift b/TINetworking/Sources/SessionFactory.swift new file mode 100644 index 00000000..275975e4 --- /dev/null +++ b/TINetworking/Sources/SessionFactory.swift @@ -0,0 +1,37 @@ +import Foundation +import Alamofire + +open class SessionFactory { + + /// Timeout interval for requests. + public var timeoutInterval: TimeInterval + + /// A dictionary of additional headers to send with requests. + public var additionalHttpHeaders: HTTPHeaders + + /// Server trust policies. + public var serverTrustPolicies: [String: ServerTrustEvaluating] + + public init(timeoutInterval: TimeInterval = 20, + additionalHttpHeaders: HTTPHeaders = HTTPHeaders(), + trustPolicies: [String: ServerTrustEvaluating] = [:]) { + + self.timeoutInterval = timeoutInterval + self.additionalHttpHeaders = additionalHttpHeaders + self.serverTrustPolicies = Dictionary(uniqueKeysWithValues: trustPolicies.map { ($0.key.urlHost, $0.value) }) + } + + open func createSession() -> Session { + Session(configuration: createSessionConfiguration(), + serverTrustManager: ServerTrustManager(allHostsMustBeEvaluated: false, + evaluators: serverTrustPolicies)) + } + + open func createSessionConfiguration() -> URLSessionConfiguration { + let sessionConfiguration = URLSessionConfiguration.default + sessionConfiguration.timeoutIntervalForResource = timeoutInterval + sessionConfiguration.httpAdditionalHeaders = additionalHttpHeaders.dictionary + + return sessionConfiguration + } +} diff --git a/TINetworking/Sources/String+URLExtensions.swift b/TINetworking/Sources/String+URLExtensions.swift new file mode 100644 index 00000000..0d722e85 --- /dev/null +++ b/TINetworking/Sources/String+URLExtensions.swift @@ -0,0 +1,17 @@ +import Foundation + +public extension String { + var urlEscaped: String { + return addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? self + } + + var urlHost: String { + URL(string: self)?.host ?? self + } + + static func render(template: String, using variables: [KeyValueTuple]) -> String { + variables.reduce(template) { + $0.replacingOccurrences(of: "{\($1.key)}", with: $1.value.urlEscaped) + } + } +} diff --git a/TINetworking/Sources/Typealiases.swift b/TINetworking/Sources/Typealiases.swift new file mode 100644 index 00000000..308efd25 --- /dev/null +++ b/TINetworking/Sources/Typealiases.swift @@ -0,0 +1 @@ +public typealias KeyValueTuple = (key: K, value: V) From 4b908f1e32ce726761e51d2095b59c9f1f0ad5ce Mon Sep 17 00:00:00 2001 From: Ilya Salatyuk Date: Thu, 5 Aug 2021 08:20:16 +0300 Subject: [PATCH 02/11] fix incorrect header handling --- .../Parameters/Encoding/HeadersParameterEncoding.swift | 6 +++--- TINetworking/Sources/Request/Request.swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift index 7c4f058a..2186026d 100644 --- a/TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift +++ b/TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift @@ -1,12 +1,12 @@ -open class HeadersParameterEncoding: BaseUrlParameterEncoding, ParameterEncoding { +open class HeadersParameterEncoding { public let sequenceSeparator: String public init(sequenceSeparator: String = ";") { self.sequenceSeparator = sequenceSeparator } - open func encode(parameters: [String: Parameter]) -> [String: String] { - Dictionary(encode(parameters: parameters)) { + open func encode(parameters: [KeyValueTuple]) -> [String: String] { + Dictionary(parameters) { $0 + sequenceSeparator + $1 } } diff --git a/TINetworking/Sources/Request/Request.swift b/TINetworking/Sources/Request/Request.swift index 3505e96e..ff1562f3 100644 --- a/TINetworking/Sources/Request/Request.swift +++ b/TINetworking/Sources/Request/Request.swift @@ -7,7 +7,7 @@ public struct Request { public var requestBodyContent: Content public var queryParameters: [String: Parameter] public var pathParameters: [String: Parameter] - public var headerParameters: [String: Parameter] + public var headerParameters: [KeyValueTuple] public var cookieParameters: [String: Parameter] public var acceptableStatusCodes: Set public var serverOverride: Server? @@ -22,7 +22,7 @@ public struct Request { requestBodyContent: Content, queryParameters: [String: Parameter] = [:], pathParameters: [String: Parameter] = [:], - headerParameters: [String: Parameter] = [:], + headerParameters: [KeyValueTuple] = [], cookieParameters: [String: Parameter] = [:], acceptableStatusCodes: Set = [200], serverOverride: Server? = nil, From ffcec6e4de0c2533e53401799aa3e7b95a9551c3 Mon Sep 17 00:00:00 2001 From: Ilya Salatyuk Date: Fri, 6 Aug 2021 00:02:32 +0300 Subject: [PATCH 03/11] replace type and remove unnecessary --- TINetworking/Sources/Parameters/ParameterEncoding.swift | 6 ------ TINetworking/Sources/Request/Request.swift | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) delete mode 100644 TINetworking/Sources/Parameters/ParameterEncoding.swift diff --git a/TINetworking/Sources/Parameters/ParameterEncoding.swift b/TINetworking/Sources/Parameters/ParameterEncoding.swift deleted file mode 100644 index ff1b362c..00000000 --- a/TINetworking/Sources/Parameters/ParameterEncoding.swift +++ /dev/null @@ -1,6 +0,0 @@ -protocol ParameterEncoding { - associatedtype Location: ParameterLocation - associatedtype Result - - func encode(parameters: [String: Parameter]) -> Result -} diff --git a/TINetworking/Sources/Request/Request.swift b/TINetworking/Sources/Request/Request.swift index ff1562f3..07a2bad2 100644 --- a/TINetworking/Sources/Request/Request.swift +++ b/TINetworking/Sources/Request/Request.swift @@ -7,7 +7,7 @@ public struct Request { public var requestBodyContent: Content public var queryParameters: [String: Parameter] public var pathParameters: [String: Parameter] - public var headerParameters: [KeyValueTuple] + public var headerParameters: HTTPHeaders? public var cookieParameters: [String: Parameter] public var acceptableStatusCodes: Set public var serverOverride: Server? @@ -22,7 +22,7 @@ public struct Request { requestBodyContent: Content, queryParameters: [String: Parameter] = [:], pathParameters: [String: Parameter] = [:], - headerParameters: [KeyValueTuple] = [], + headerParameters: HTTPHeaders? = nil, cookieParameters: [String: Parameter] = [:], acceptableStatusCodes: Set = [200], serverOverride: Server? = nil, From b1cc752af3cf3945f9e3809d88eca837a7a8900c Mon Sep 17 00:00:00 2001 From: Ilya Salatyuk Date: Fri, 6 Aug 2021 17:35:25 +0300 Subject: [PATCH 04/11] recovery files and remove unnecessary --- .../Encoding/HeadersParameterEncoding.swift | 13 ------------- .../Sources/Parameters/ParameterEncoding.swift | 6 ++++++ 2 files changed, 6 insertions(+), 13 deletions(-) delete mode 100644 TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift create mode 100644 TINetworking/Sources/Parameters/ParameterEncoding.swift diff --git a/TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift deleted file mode 100644 index 2186026d..00000000 --- a/TINetworking/Sources/Parameters/Encoding/HeadersParameterEncoding.swift +++ /dev/null @@ -1,13 +0,0 @@ -open class HeadersParameterEncoding { - public let sequenceSeparator: String - - public init(sequenceSeparator: String = ";") { - self.sequenceSeparator = sequenceSeparator - } - - open func encode(parameters: [KeyValueTuple]) -> [String: String] { - Dictionary(parameters) { - $0 + sequenceSeparator + $1 - } - } -} diff --git a/TINetworking/Sources/Parameters/ParameterEncoding.swift b/TINetworking/Sources/Parameters/ParameterEncoding.swift new file mode 100644 index 00000000..58608ec9 --- /dev/null +++ b/TINetworking/Sources/Parameters/ParameterEncoding.swift @@ -0,0 +1,6 @@ +protocol ParameterEncoding { + associatedtype Location: ParameterLocation + associatedtype Result + + func encode(parameters: [String: Parameter]) -> Result +} \ No newline at end of file From 89a3bfe6974d6f73a448bde1d57a3e5d891cb816 Mon Sep 17 00:00:00 2001 From: Ivan Smolin Date: Mon, 13 Sep 2021 19:12:08 +0300 Subject: [PATCH 05/11] ResponseType decoding simplified and other enhancements --- .../Sources/Mapping/BaseContent.swift | 9 ++++ .../ApplicationJsonBodyContent.swift | 2 +- .../BodyContent/EmptyBodyContent.swift | 8 +--- .../Sources/Mapping/Codable+Required.swift | 4 +- ...MediaType.swift => CommonMediaTypes.swift} | 2 +- .../ApplicationJsonResponseContent.swift | 8 +++- .../EmptyResponseContent.swift | 7 +++ .../ResponseContent/MapResponseContent.swift | 18 ++++++++ .../TextPlainResponseContent.swift | 6 +-- .../Response/ResponseType+Decoding.swift | 44 +++++++------------ 10 files changed, 67 insertions(+), 41 deletions(-) create mode 100644 TINetworking/Sources/Mapping/BaseContent.swift rename TINetworking/Sources/Mapping/{MediaType.swift => CommonMediaTypes.swift} (67%) create mode 100644 TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift diff --git a/TINetworking/Sources/Mapping/BaseContent.swift b/TINetworking/Sources/Mapping/BaseContent.swift new file mode 100644 index 00000000..46d4bca3 --- /dev/null +++ b/TINetworking/Sources/Mapping/BaseContent.swift @@ -0,0 +1,9 @@ +import Foundation + +open class BaseContent: Content { + public let mediaTypeName: String + + public init(mediaTypeName: String = CommonMediaTypes.textPlain.rawValue) { + self.mediaTypeName = mediaTypeName + } +} diff --git a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift index 316b3113..694361ea 100644 --- a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift +++ b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift @@ -2,7 +2,7 @@ import Foundation open class ApplicationJsonBodyContent: BodyContent { public var mediaTypeName: String { - MediaType.applicationJson.rawValue + CommonMediaTypes.applicationJson.rawValue } private let encodingClosure: () throws -> Data diff --git a/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift index 12d1579f..0bb0fb86 100644 --- a/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift +++ b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift @@ -1,12 +1,6 @@ import Foundation -public struct EmptyBodyContent: BodyContent { - public var mediaTypeName: String { - MediaType.textPlain.rawValue - } - - public init() {} - +public final class EmptyBodyContent: BaseContent, BodyContent { public func encodeBody() throws -> Data { Data() } diff --git a/TINetworking/Sources/Mapping/Codable+Required.swift b/TINetworking/Sources/Mapping/Codable+Required.swift index 8cceb3b6..54d3a195 100644 --- a/TINetworking/Sources/Mapping/Codable+Required.swift +++ b/TINetworking/Sources/Mapping/Codable+Required.swift @@ -3,7 +3,9 @@ public extension KeyedDecodingContainer { forKey key: Key, required: Bool) throws -> T? { - required ? try decode(type, forKey: key) : try decodeIfPresent(T.self, forKey: key) + required + ? try decode(type, forKey: key) + : try decodeIfPresent(T.self, forKey: key) } } diff --git a/TINetworking/Sources/Mapping/MediaType.swift b/TINetworking/Sources/Mapping/CommonMediaTypes.swift similarity index 67% rename from TINetworking/Sources/Mapping/MediaType.swift rename to TINetworking/Sources/Mapping/CommonMediaTypes.swift index 387a36f1..3e9999ab 100644 --- a/TINetworking/Sources/Mapping/MediaType.swift +++ b/TINetworking/Sources/Mapping/CommonMediaTypes.swift @@ -1,4 +1,4 @@ -public enum MediaType: String { +public enum CommonMediaTypes: String { case applicationJson = "application/json" case textPlain = "text/plain" } diff --git a/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift index 498ea08b..dba84b3e 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift @@ -2,7 +2,7 @@ import Foundation open class ApplicationJsonResponseContent: ResponseContent { public var mediaTypeName: String { - MediaType.applicationJson.rawValue + CommonMediaTypes.applicationJson.rawValue } public let jsonDecoder: JSONDecoder @@ -15,3 +15,9 @@ open class ApplicationJsonResponseContent: ResponseContent { try jsonDecoder.decode(Model.self, from: data) } } + +public extension JSONDecoder { + func responseContent() -> ApplicationJsonResponseContent { + .init(jsonDecoder: self) + } +} diff --git a/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift new file mode 100644 index 00000000..fb1ffdb2 --- /dev/null +++ b/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift @@ -0,0 +1,7 @@ +import Foundation + +open class EmptyResponseContent: BaseContent, ResponseContent { + public func decodeResponse(data: Data) throws -> Void { + () + } +} diff --git a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift index ebcca1c0..3686bc10 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift @@ -16,3 +16,21 @@ public struct MapResponseContent: ResponseContent { try decodeClosure(data) } } + +public extension ResponseContent { + typealias TransformClosure = (Model) -> T + + func map(_ transform: @escaping TransformClosure) -> MapResponseContent { + .init(responseContent: self, transform: transform) + } +} + +public extension JSONDecoder { + func responseContent(_ tranfsorm: @escaping (T) -> R) -> MapResponseContent { + responseContent().map(tranfsorm) + } + + func decoding(to tranfsorm: @escaping (T) -> R) -> (Data) throws -> R { + responseContent(tranfsorm).decodeResponse + } +} diff --git a/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift index ebfa6c73..fef074a1 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift @@ -1,7 +1,7 @@ import Foundation public struct TextPlainResponseContent: ResponseContent { - struct UnableToDecodeStringError: Error { + struct StringDecodingError: Error { let data: Data let encoding: String.Encoding } @@ -12,11 +12,11 @@ public struct TextPlainResponseContent: ResponseContent { self.encoding = encoding } - public let mediaTypeName = MediaType.textPlain.rawValue + public let mediaTypeName = CommonMediaTypes.textPlain.rawValue public func decodeResponse(data: Data) throws -> String { guard let plainText = String(data: data, encoding: encoding) else { - throw UnableToDecodeStringError(data: data, encoding: encoding) + throw StringDecodingError(data: data, encoding: encoding) } return plainText diff --git a/TINetworking/Sources/Response/ResponseType+Decoding.swift b/TINetworking/Sources/Response/ResponseType+Decoding.swift index e1f475a5..fc482a72 100644 --- a/TINetworking/Sources/Response/ResponseType+Decoding.swift +++ b/TINetworking/Sources/Response/ResponseType+Decoding.swift @@ -1,45 +1,35 @@ -public struct ResponseTypeDecodingError: Error { - public let statusCode: Int - public let contentType: String -} +import Foundation -public struct ContentMapping { - public let statusCode: Int - public let mimeType: String? - public let responseContent: Content - - public init(statusCode: Int, mimeType: String?, responseContent: Content) { - self.statusCode = statusCode - self.mimeType = mimeType - self.responseContent = responseContent - } - - public func map(transform: @escaping (Content.Model) -> NewModel) -> ContentMapping> { - .init(statusCode: statusCode, - mimeType: mimeType, - responseContent: MapResponseContent(responseContent: responseContent, - transform: transform)) - } -} +public typealias StatusCodeMimeType = (statusCode: Int, mimeType: String?) +public typealias StatusCodesMimeType = (statusCodes: Set, mimeType: String?) public extension ResponseType { - func decode(contentMapping: [ContentMapping]) -> Result { - for mapping in contentMapping where mapping.statusCode == statusCode && mapping.mimeType == mimeType { + typealias DecodingClosure = (Data) throws -> R + + func decode(mapping: [KeyValueTuple>]) -> Result { + for ((mappingStatusCode, mappingMimeType), decodeClosure) in mapping + where mappingStatusCode == statusCode && mappingMimeType == mimeType { do { - return .success(try mapping.responseContent.decodeResponse(data: data)) + return .success(try decodeClosure(data)) } catch { return .failure(objectMappingError(underlyingError: error)) } } - guard contentMapping.contains(where: { $0.statusCode == statusCode }) else { + guard mapping.contains(where: { $0.key.statusCode == statusCode }) else { return .failure(unsupportedStatusCodeError(statusCode: statusCode)) } - guard contentMapping.contains(where: { $0.mimeType == mimeType }) else { + guard mapping.contains(where: { $0.key.mimeType == mimeType }) else { return .failure(unsupportedMimeTypeError(mimeType: mimeType)) } return .failure(unsupportedStatusCodeMimeTypePairError(statusCode: statusCode, mimeType: mimeType)) } + + func decode(mapping: [KeyValueTuple>]) -> Result { + decode(mapping: mapping.map { key, value in + key.statusCodes.map { KeyValueTuple(StatusCodeMimeType($0, key.mimeType), value) } + }.flatMap { $0 }) + } } From 3dd6fa98300c5d6712e034b2f3aca388a33a5a7c Mon Sep 17 00:00:00 2001 From: Ivan Smolin Date: Tue, 14 Sep 2021 16:58:02 +0300 Subject: [PATCH 06/11] move DecodingClosure out of ResponseType --- TINetworking/Sources/Response/ResponseType+Decoding.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TINetworking/Sources/Response/ResponseType+Decoding.swift b/TINetworking/Sources/Response/ResponseType+Decoding.swift index fc482a72..558a76d6 100644 --- a/TINetworking/Sources/Response/ResponseType+Decoding.swift +++ b/TINetworking/Sources/Response/ResponseType+Decoding.swift @@ -3,9 +3,9 @@ import Foundation public typealias StatusCodeMimeType = (statusCode: Int, mimeType: String?) public typealias StatusCodesMimeType = (statusCodes: Set, mimeType: String?) -public extension ResponseType { - typealias DecodingClosure = (Data) throws -> R +public typealias DecodingClosure = (Data) throws -> R +public extension ResponseType { func decode(mapping: [KeyValueTuple>]) -> Result { for ((mappingStatusCode, mappingMimeType), decodeClosure) in mapping where mappingStatusCode == statusCode && mappingMimeType == mimeType { From 1fcc47837272668e6b27b16c3770a711126fcd4c Mon Sep 17 00:00:00 2001 From: Ivan Smolin Date: Tue, 14 Sep 2021 17:15:42 +0300 Subject: [PATCH 07/11] build: add podspec for TINetworking & update version --- CHANGELOG.md | 3 +++ LeadKit.podspec | 2 +- TIFoundationUtils/TIFoundationUtils.podspec | 2 +- TIKeychainUtils/TIKeychainUtils.podspec | 2 +- TINetworking/TINetworking.podspec | 16 ++++++++++++++++ TISwiftUtils/TISwiftUtils.podspec | 2 +- TITableKitUtils/TITableKitUtils.podspec | 2 +- TITransitions/TITransitions.podspec | 2 +- TIUIElements/TIUIElements.podspec | 2 +- TIUIKitCore/TIUIKitCore.podspec | 2 +- 10 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 TINetworking/TINetworking.podspec diff --git a/CHANGELOG.md b/CHANGELOG.md index 1501693d..1460e05a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +### 1.6.0 +- **Add**: `TINetworking` - Swagger-frendly networking layer helpers + ### 1.5.0 - **Add**: `HeaderTransitionDelegate` - Helper for transition of TableView header and navigationBar title view diff --git a/LeadKit.podspec b/LeadKit.podspec index 526e2d80..03d8ca8c 100644 --- a/LeadKit.podspec +++ b/LeadKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "LeadKit" - s.version = "1.5.1" + s.version = "1.6.0" 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/TIFoundationUtils/TIFoundationUtils.podspec b/TIFoundationUtils/TIFoundationUtils.podspec index 90ecabc9..2079438d 100644 --- a/TIFoundationUtils/TIFoundationUtils.podspec +++ b/TIFoundationUtils/TIFoundationUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIFoundationUtils' - s.version = '1.5.1' + s.version = '1.6.0' s.summary = 'Set of helpers for Foundation framework classes.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIKeychainUtils/TIKeychainUtils.podspec b/TIKeychainUtils/TIKeychainUtils.podspec index 567c34eb..407932f6 100644 --- a/TIKeychainUtils/TIKeychainUtils.podspec +++ b/TIKeychainUtils/TIKeychainUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIKeychainUtils' - s.version = '1.5.1' + s.version = '1.6.0' s.summary = 'Set of helpers for Keychain classes.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TINetworking/TINetworking.podspec b/TINetworking/TINetworking.podspec new file mode 100644 index 00000000..15ccdbff --- /dev/null +++ b/TINetworking/TINetworking.podspec @@ -0,0 +1,16 @@ +Pod::Spec.new do |s| + s.name = 'TINetworking' + s.version = '1.6.0' + s.summary = 'Swagger-frendly networking layer helpers.' + s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name + s.license = { :type => 'MIT', :file => 'LICENSE' } + s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' } + s.source = { :git => 'https://github.com/TouchInstinct/LeadKit.git', :tag => s.version.to_s } + + s.ios.deployment_target = '10.0' + s.swift_versions = ['5.3'] + + s.source_files = s.name + '/Sources/**/*' + + s.dependency 'Alamofire' +end diff --git a/TISwiftUtils/TISwiftUtils.podspec b/TISwiftUtils/TISwiftUtils.podspec index 7e7e8493..e3fbf696 100644 --- a/TISwiftUtils/TISwiftUtils.podspec +++ b/TISwiftUtils/TISwiftUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TISwiftUtils' - s.version = '1.5.1' + s.version = '1.6.0' s.summary = 'Bunch of useful helpers for Swift development.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TITableKitUtils/TITableKitUtils.podspec b/TITableKitUtils/TITableKitUtils.podspec index cdcfa5e8..c62ddc09 100644 --- a/TITableKitUtils/TITableKitUtils.podspec +++ b/TITableKitUtils/TITableKitUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TITableKitUtils' - s.version = '1.5.1' + s.version = '1.6.0' s.summary = 'Set of helpers for TableKit classes.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TITransitions/TITransitions.podspec b/TITransitions/TITransitions.podspec index 561c6a75..0f4cc5e2 100644 --- a/TITransitions/TITransitions.podspec +++ b/TITransitions/TITransitions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TITransitions' - s.version = '1.5.1' + s.version = '1.6.0' s.summary = 'Set of custom transitions to present controller. ' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIUIElements/TIUIElements.podspec b/TIUIElements/TIUIElements.podspec index 26a60423..759d9fcc 100644 --- a/TIUIElements/TIUIElements.podspec +++ b/TIUIElements/TIUIElements.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIUIElements' - s.version = '1.5.1' + s.version = '1.6.0' s.summary = 'Bunch of useful protocols and views.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIUIKitCore/TIUIKitCore.podspec b/TIUIKitCore/TIUIKitCore.podspec index 9498c4a0..0a863b71 100644 --- a/TIUIKitCore/TIUIKitCore.podspec +++ b/TIUIKitCore/TIUIKitCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIUIKitCore' - s.version = '1.5.1' + s.version = '1.6.0' s.summary = 'Core UI elements: protocols, views and helpers.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } From c2df8511f2641f3650ce721b672fae3afe6ba905 Mon Sep 17 00:00:00 2001 From: Ivan Smolin Date: Fri, 17 Sep 2021 19:45:06 +0300 Subject: [PATCH 08/11] refactor: fix code review notes --- .../ApplicationJsonBodyContent.swift | 14 +++++++------- .../Mapping/BodyContent/EmptyBodyContent.swift | 6 ++++++ .../Mapping/OneOfMapping/AnyTypeMapping.swift | 3 ++- .../OneOfMapping/OneOfMappingError.swift | 2 +- .../ApplicationJsonResponseContent.swift | 8 +++----- .../ResponseContent/EmptyResponseContent.swift | 2 +- .../ResponseContent/MapResponseContent.swift | 8 ++++---- .../TextPlainResponseContent.swift | 6 +++++- .../Encoding/BaseUrlParameterEncoding.swift | 17 ++++++----------- TINetworking/Sources/Request/Request.swift | 12 ++++++------ .../Response/MimeTypeUnsupportedError.swift | 8 +++++--- ...StatusCodeMimeTypePairUnsupportedError.swift | 10 ++++++---- TINetworking/Sources/Server.swift | 8 ++++---- TINetworking/Sources/SessionFactory.swift | 5 ----- 14 files changed, 56 insertions(+), 53 deletions(-) diff --git a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift index 694361ea..ab839bfa 100644 --- a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift +++ b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift @@ -1,22 +1,22 @@ import Foundation -open class ApplicationJsonBodyContent: BodyContent { - public var mediaTypeName: String { - CommonMediaTypes.applicationJson.rawValue - } - +open class ApplicationJsonBodyContent: BaseContent, BodyContent { private let encodingClosure: () throws -> Data public init(body: Body, jsonEncoder: JSONEncoder = JSONEncoder()) where Body: Encodable { - self.encodingClosure = { + encodingClosure = { try jsonEncoder.encode(body) } + + super.init(mediaTypeName: CommonMediaTypes.applicationJson.rawValue) } public init(jsonBody: Body, options: JSONSerialization.WritingOptions = .prettyPrinted) { - self.encodingClosure = { + encodingClosure = { try JSONSerialization.data(withJSONObject: jsonBody, options: options) } + + super.init(mediaTypeName: CommonMediaTypes.applicationJson.rawValue) } public func encodeBody() throws -> Data { diff --git a/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift index 0bb0fb86..c0b634ac 100644 --- a/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift +++ b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift @@ -5,3 +5,9 @@ public final class EmptyBodyContent: BaseContent, BodyContent { Data() } } + +public extension BodyContent { + static var empty: EmptyBodyContent { + .init() + } +} diff --git a/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift b/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift index b1b97cb2..9a13b1fd 100644 --- a/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift +++ b/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift @@ -1,7 +1,8 @@ public struct AnyTypeMapping { - public let type: Any.Type private let mappingClosure: () -> Result + public let type: Any.Type + public init(decoder: Decoder, transform: @escaping (T) -> R) { diff --git a/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift b/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift index c7c025b8..4dd16f20 100644 --- a/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift +++ b/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift @@ -10,7 +10,7 @@ public struct OneOfMappingError: Error, CustomDebugStringConvertible { } public var debugDescription: String { - var formattedString = "OneOf mapping failed for codingPath \(codingPath)\nwith following errors:\n" + var formattedString = "\"oneOf\" mapping failed for codingPath \(codingPath)\nwith following errors:\n" for (type, error) in mappingFailures { formattedString += "\(type) mapping failed with error: \(error)\n" diff --git a/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift index dba84b3e..164dbe6b 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift @@ -1,14 +1,12 @@ import Foundation -open class ApplicationJsonResponseContent: ResponseContent { - public var mediaTypeName: String { - CommonMediaTypes.applicationJson.rawValue - } - +open class ApplicationJsonResponseContent: BaseContent, ResponseContent { public let jsonDecoder: JSONDecoder public init(jsonDecoder: JSONDecoder = JSONDecoder()) { self.jsonDecoder = jsonDecoder + + super.init(mediaTypeName: CommonMediaTypes.applicationJson.rawValue) } public func decodeResponse(data: Data) throws -> Model { diff --git a/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift index fb1ffdb2..c9c3200e 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift @@ -1,6 +1,6 @@ import Foundation -open class EmptyResponseContent: BaseContent, ResponseContent { +public final class EmptyResponseContent: BaseContent, ResponseContent { public func decodeResponse(data: Data) throws -> Void { () } diff --git a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift index 3686bc10..eda890e4 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift @@ -1,13 +1,13 @@ import Foundation public struct MapResponseContent: ResponseContent { - public let mediaTypeName: String - private let decodeClosure: (Data) throws -> Model + public let mediaTypeName: String + public init(responseContent: C, transform: @escaping (C.Model) -> Model) { - self.mediaTypeName = responseContent.mediaTypeName - self.decodeClosure = { + mediaTypeName = responseContent.mediaTypeName + decodeClosure = { transform(try responseContent.decodeResponse(data: $0)) } } diff --git a/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift index fef074a1..e54c9fea 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift @@ -8,11 +8,15 @@ public struct TextPlainResponseContent: ResponseContent { private let encoding: String.Encoding + // MARK: - Content + + public let mediaTypeName = CommonMediaTypes.textPlain.rawValue + public init(encoding: String.Encoding = .utf8) { self.encoding = encoding } - public let mediaTypeName = CommonMediaTypes.textPlain.rawValue + // MARK: - ResponseContent public func decodeResponse(data: Data) throws -> String { guard let plainText = String(data: data, encoding: encoding) else { diff --git a/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift index 85b1c119..644091d0 100644 --- a/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift +++ b/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift @@ -3,26 +3,21 @@ import Alamofire open class BaseUrlParameterEncoding { private let encoding: URLEncoding = .queryString - public init() { - } + public init() {} open func encode(parameters: [String: Parameter]) -> [KeyValueTuple] { - var filteredComponents: [(String, String)] = [] + var filteredComponents: [KeyValueTuple] = [] for key in parameters.keys.sorted(by: <) { guard let parameter = parameters[key] else { continue } - let components: [KeyValueTuple] = encoding.queryComponents(fromKey: key, value: parameter.value) + let components = encoding.queryComponents(fromKey: key, value: parameter.value) + // filter components with empty values if parameter doesn't allow empty value + .filter { !$0.1.isEmpty || parameter.allowEmptyValue } - for component in components { - if component.value.isEmpty && !parameter.allowEmptyValue { - continue - } - - filteredComponents.append(component) - } + filteredComponents.append(contentsOf: components) } return filteredComponents diff --git a/TINetworking/Sources/Request/Request.swift b/TINetworking/Sources/Request/Request.swift index 07a2bad2..3949c9cb 100644 --- a/TINetworking/Sources/Request/Request.swift +++ b/TINetworking/Sources/Request/Request.swift @@ -10,8 +10,8 @@ public struct Request { public var headerParameters: HTTPHeaders? public var cookieParameters: [String: Parameter] public var acceptableStatusCodes: Set - public var serverOverride: Server? - public var serverVariablesOverride: [KeyValueTuple] + public var customServer: Server? + public var customServerVariables: [KeyValueTuple] public var path: String { PathParameterEncoding(templateUrl: templatePath).encode(parameters: pathParameters) @@ -25,8 +25,8 @@ public struct Request { headerParameters: HTTPHeaders? = nil, cookieParameters: [String: Parameter] = [:], acceptableStatusCodes: Set = [200], - serverOverride: Server? = nil, - serverVariablesOverride: [KeyValueTuple] = []) { + customServer: Server? = nil, + customServerVariables: [KeyValueTuple] = []) { self.templatePath = templatePath self.method = method @@ -36,7 +36,7 @@ public struct Request { self.headerParameters = headerParameters self.cookieParameters = cookieParameters self.acceptableStatusCodes = acceptableStatusCodes - self.serverOverride = serverOverride - self.serverVariablesOverride = serverVariablesOverride + self.customServer = customServer + self.customServerVariables = customServerVariables } } diff --git a/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift b/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift index 8a885b58..ffa29c19 100644 --- a/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift +++ b/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift @@ -2,11 +2,13 @@ open class MimeTypeUnsupportedError: Error, CustomDebugStringConvertible { public let mimeType: String? - public init(mimeType: String?) { - self.mimeType = mimeType - } + // MARK: - CustomDebugStringConvertible public var debugDescription: String { "Mime type \(mimeType.debugDescription) isn't supported." } + + public init(mimeType: String?) { + self.mimeType = mimeType + } } diff --git a/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift b/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift index 909c20a9..3563dcc4 100644 --- a/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift +++ b/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift @@ -2,13 +2,15 @@ open class StatusCodeMimeTypePairUnsupportedError: MimeTypeUnsupportedError { public let statusCode: Int + // MARK: - CustomDebugStringConvertible + + public override var debugDescription: String { + "Status code: \(statusCode), mimeType: \(mimeType ?? "nil") pair is unsupported!" + } + public init(statusCode: Int, mimeType: String?) { self.statusCode = statusCode super.init(mimeType: mimeType) } - - public override var debugDescription: String { - "Status code: \(statusCode), mimeType: \(mimeType ?? "nil") pair is unsupported!" - } } diff --git a/TINetworking/Sources/Server.swift b/TINetworking/Sources/Server.swift index 2d3a11c3..facbe7c9 100644 --- a/TINetworking/Sources/Server.swift +++ b/TINetworking/Sources/Server.swift @@ -19,6 +19,10 @@ public struct Server { } } + private var defaultVariables: [KeyValueTuple] { + variables.map { ($0.key, $0.value.defaultValue) } + } + public let urlTemplate: String public let variables: [String: Variable] @@ -31,10 +35,6 @@ public struct Server { self.init(urlTemplate: baseUrl, variables: [:]) } - private var defaultVariables: [KeyValueTuple] { - variables.map { ($0.key, $0.value.defaultValue) } - } - public func url(using variables: [KeyValueTuple] = [], appendHttpsSchemeIfMissing: Bool = true) -> URL? { diff --git a/TINetworking/Sources/SessionFactory.swift b/TINetworking/Sources/SessionFactory.swift index 275975e4..816382f5 100644 --- a/TINetworking/Sources/SessionFactory.swift +++ b/TINetworking/Sources/SessionFactory.swift @@ -3,13 +3,8 @@ import Alamofire open class SessionFactory { - /// Timeout interval for requests. public var timeoutInterval: TimeInterval - - /// A dictionary of additional headers to send with requests. public var additionalHttpHeaders: HTTPHeaders - - /// Server trust policies. public var serverTrustPolicies: [String: ServerTrustEvaluating] public init(timeoutInterval: TimeInterval = 20, From b8550bd8d56a942f94d19a5ff3b05cb2b3d3c458 Mon Sep 17 00:00:00 2001 From: Ivan Smolin Date: Fri, 17 Sep 2021 19:55:31 +0300 Subject: [PATCH 09/11] refactor: use TISwiftUtils in TINetworking --- Package.swift | 2 +- .../BodyContent/ApplicationJsonBodyContent.swift | 3 ++- .../Sources/Mapping/OneOfMapping/AnyTypeMapping.swift | 6 ++++-- .../Mapping/ResponseContent/MapResponseContent.swift | 11 ++++++----- .../Sources/Response/ResponseType+Decoding.swift | 3 ++- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Package.swift b/Package.swift index 17d592ad..03aebe37 100644 --- a/Package.swift +++ b/Package.swift @@ -41,7 +41,7 @@ let package = Package( .target(name: "TIFoundationUtils", dependencies: ["TISwiftUtils"], path: "TIFoundationUtils/Sources"), .target(name: "TIKeychainUtils", dependencies: ["TIFoundationUtils", "KeychainAccess"], path: "TIKeychainUtils/Sources"), .target(name: "TITableKitUtils", dependencies: ["TIUIElements", "TableKit"], path: "TITableKitUtils/Sources"), - .target(name: "TINetworking", dependencies: ["Alamofire"], path: "TINetworking/Sources"), + .target(name: "TINetworking", dependencies: ["TISwiftUtils", "Alamofire"], path: "TINetworking/Sources"), // MARK: - Elements diff --git a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift index ab839bfa..5e4a1734 100644 --- a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift +++ b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift @@ -1,7 +1,8 @@ import Foundation +import TISwiftUtils open class ApplicationJsonBodyContent: BaseContent, BodyContent { - private let encodingClosure: () throws -> Data + private let encodingClosure: ThrowableResultClosure public init(body: Body, jsonEncoder: JSONEncoder = JSONEncoder()) where Body: Encodable { encodingClosure = { diff --git a/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift b/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift index 9a13b1fd..02a2181b 100644 --- a/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift +++ b/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift @@ -1,10 +1,12 @@ +import TISwiftUtils + public struct AnyTypeMapping { - private let mappingClosure: () -> Result + private let mappingClosure: ResultClosure> public let type: Any.Type public init(decoder: Decoder, - transform: @escaping (T) -> R) { + transform: @escaping Closure) { type = T.self diff --git a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift index eda890e4..04e53ded 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift @@ -1,11 +1,12 @@ import Foundation +import TISwiftUtils public struct MapResponseContent: ResponseContent { - private let decodeClosure: (Data) throws -> Model + private let decodeClosure: ThrowableClosure public let mediaTypeName: String - public init(responseContent: C, transform: @escaping (C.Model) -> Model) { + public init(responseContent: C, transform: @escaping Closure) { mediaTypeName = responseContent.mediaTypeName decodeClosure = { transform(try responseContent.decodeResponse(data: $0)) @@ -18,7 +19,7 @@ public struct MapResponseContent: ResponseContent { } public extension ResponseContent { - typealias TransformClosure = (Model) -> T + typealias TransformClosure = Closure func map(_ transform: @escaping TransformClosure) -> MapResponseContent { .init(responseContent: self, transform: transform) @@ -26,11 +27,11 @@ public extension ResponseContent { } public extension JSONDecoder { - func responseContent(_ tranfsorm: @escaping (T) -> R) -> MapResponseContent { + func responseContent(_ tranfsorm: @escaping Closure) -> MapResponseContent { responseContent().map(tranfsorm) } - func decoding(to tranfsorm: @escaping (T) -> R) -> (Data) throws -> R { + func decoding(to tranfsorm: @escaping Closure) -> ThrowableClosure { responseContent(tranfsorm).decodeResponse } } diff --git a/TINetworking/Sources/Response/ResponseType+Decoding.swift b/TINetworking/Sources/Response/ResponseType+Decoding.swift index 558a76d6..b1ef2228 100644 --- a/TINetworking/Sources/Response/ResponseType+Decoding.swift +++ b/TINetworking/Sources/Response/ResponseType+Decoding.swift @@ -1,9 +1,10 @@ import Foundation +import TISwiftUtils public typealias StatusCodeMimeType = (statusCode: Int, mimeType: String?) public typealias StatusCodesMimeType = (statusCodes: Set, mimeType: String?) -public typealias DecodingClosure = (Data) throws -> R +public typealias DecodingClosure = ThrowableClosure public extension ResponseType { func decode(mapping: [KeyValueTuple>]) -> Result { From 8397f15ec5941bcc24b3e9665cbc324362ac0dee Mon Sep 17 00:00:00 2001 From: Ivan Smolin Date: Mon, 27 Sep 2021 10:55:32 +0300 Subject: [PATCH 10/11] docs: add copyrights --- .../Sources/Mapping/BaseContent.swift | 22 +++++++++++++++++++ .../ApplicationJsonBodyContent.swift | 22 +++++++++++++++++++ .../Mapping/BodyContent/BodyContent.swift | 22 +++++++++++++++++++ .../BodyContent/EmptyBodyContent.swift | 22 +++++++++++++++++++ .../Sources/Mapping/Codable+Required.swift | 22 +++++++++++++++++++ .../Sources/Mapping/CommonMediaTypes.swift | 22 +++++++++++++++++++ TINetworking/Sources/Mapping/Content.swift | 22 +++++++++++++++++++ .../Mapping/OneOfMapping/AnyTypeMapping.swift | 22 +++++++++++++++++++ .../OneOfMapping/OneOfMappingError.swift | 22 +++++++++++++++++++ .../ApplicationJsonResponseContent.swift | 22 +++++++++++++++++++ .../EmptyResponseContent.swift | 22 +++++++++++++++++++ .../ResponseContent/MapResponseContent.swift | 22 +++++++++++++++++++ .../ResponseContent/ResponseContent.swift | 22 +++++++++++++++++++ .../TextPlainResponseContent.swift | 22 +++++++++++++++++++ .../Encoding/BaseUrlParameterEncoding.swift | 22 +++++++++++++++++++ .../Encoding/PathParameterEncoding.swift | 22 +++++++++++++++++++ .../QueryStringParameterEncoding.swift | 22 +++++++++++++++++++ .../Sources/Parameters/Parameter.swift | 22 +++++++++++++++++++ .../Parameters/ParameterEncoding.swift | 22 +++++++++++++++++++ .../Parameters/ParameterLocation.swift | 22 +++++++++++++++++++ TINetworking/Sources/Request/Request.swift | 22 +++++++++++++++++++ .../Response/MimeTypeUnsupportedError.swift | 22 +++++++++++++++++++ .../Response/ResponseType+Decoding.swift | 22 +++++++++++++++++++ .../Sources/Response/ResponseType.swift | 22 +++++++++++++++++++ ...atusCodeMimeTypePairUnsupportedError.swift | 22 +++++++++++++++++++ TINetworking/Sources/Server.swift | 22 +++++++++++++++++++ TINetworking/Sources/SessionFactory.swift | 22 +++++++++++++++++++ .../Sources/String+URLExtensions.swift | 22 +++++++++++++++++++ TINetworking/Sources/Typealiases.swift | 22 +++++++++++++++++++ 29 files changed, 638 insertions(+) diff --git a/TINetworking/Sources/Mapping/BaseContent.swift b/TINetworking/Sources/Mapping/BaseContent.swift index 46d4bca3..b91c5b6d 100644 --- a/TINetworking/Sources/Mapping/BaseContent.swift +++ b/TINetworking/Sources/Mapping/BaseContent.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation open class BaseContent: Content { diff --git a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift index 5e4a1734..f517c503 100644 --- a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift +++ b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation import TISwiftUtils diff --git a/TINetworking/Sources/Mapping/BodyContent/BodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/BodyContent.swift index 58093c6c..e055fa9a 100644 --- a/TINetworking/Sources/Mapping/BodyContent/BodyContent.swift +++ b/TINetworking/Sources/Mapping/BodyContent/BodyContent.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation public protocol BodyContent: Content { diff --git a/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift index c0b634ac..23b5593e 100644 --- a/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift +++ b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation public final class EmptyBodyContent: BaseContent, BodyContent { diff --git a/TINetworking/Sources/Mapping/Codable+Required.swift b/TINetworking/Sources/Mapping/Codable+Required.swift index 54d3a195..634f7d6c 100644 --- a/TINetworking/Sources/Mapping/Codable+Required.swift +++ b/TINetworking/Sources/Mapping/Codable+Required.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + public extension KeyedDecodingContainer { func decode(_ type: T?.Type, forKey key: Key, diff --git a/TINetworking/Sources/Mapping/CommonMediaTypes.swift b/TINetworking/Sources/Mapping/CommonMediaTypes.swift index 3e9999ab..b925af5f 100644 --- a/TINetworking/Sources/Mapping/CommonMediaTypes.swift +++ b/TINetworking/Sources/Mapping/CommonMediaTypes.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + public enum CommonMediaTypes: String { case applicationJson = "application/json" case textPlain = "text/plain" diff --git a/TINetworking/Sources/Mapping/Content.swift b/TINetworking/Sources/Mapping/Content.swift index 41b26a9b..b5735b3b 100644 --- a/TINetworking/Sources/Mapping/Content.swift +++ b/TINetworking/Sources/Mapping/Content.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + public protocol Content { var mediaTypeName: String { get } } diff --git a/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift b/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift index 02a2181b..2e92361e 100644 --- a/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift +++ b/TINetworking/Sources/Mapping/OneOfMapping/AnyTypeMapping.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import TISwiftUtils public struct AnyTypeMapping { diff --git a/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift b/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift index 4dd16f20..501adc40 100644 --- a/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift +++ b/TINetworking/Sources/Mapping/OneOfMapping/OneOfMappingError.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + public struct OneOfMappingError: Error, CustomDebugStringConvertible { public typealias MappingFailures = [KeyValueTuple] diff --git a/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift index 164dbe6b..be01234a 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation open class ApplicationJsonResponseContent: BaseContent, ResponseContent { diff --git a/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift index c9c3200e..32aaec1e 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/EmptyResponseContent.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation public final class EmptyResponseContent: BaseContent, ResponseContent { diff --git a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift index 04e53ded..f61b983e 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation import TISwiftUtils diff --git a/TINetworking/Sources/Mapping/ResponseContent/ResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/ResponseContent.swift index 3d600f79..91cdd16c 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/ResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/ResponseContent.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation public protocol ResponseContent: Content { diff --git a/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift index e54c9fea..16146104 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation public struct TextPlainResponseContent: ResponseContent { diff --git a/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift index 644091d0..90a9f75c 100644 --- a/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift +++ b/TINetworking/Sources/Parameters/Encoding/BaseUrlParameterEncoding.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Alamofire open class BaseUrlParameterEncoding { diff --git a/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift index f9501c5f..4bd1148c 100644 --- a/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift +++ b/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + open class PathParameterEncoding: BaseUrlParameterEncoding, ParameterEncoding { public let templateUrl: String diff --git a/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift index bef188bb..8b7353ff 100644 --- a/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift +++ b/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + open class QueryStringParameterEncoding: BaseUrlParameterEncoding, ParameterEncoding { open func encode(parameters: [String: Parameter]) -> [String: Any] { let includedKeys = Set(super.encode(parameters: parameters).map { $0.key }) diff --git a/TINetworking/Sources/Parameters/Parameter.swift b/TINetworking/Sources/Parameters/Parameter.swift index 5158c7dd..a1dab8a5 100644 --- a/TINetworking/Sources/Parameters/Parameter.swift +++ b/TINetworking/Sources/Parameters/Parameter.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + public struct Parameter { public let value: Any public let allowEmptyValue: Bool diff --git a/TINetworking/Sources/Parameters/ParameterEncoding.swift b/TINetworking/Sources/Parameters/ParameterEncoding.swift index 58608ec9..2cc471c2 100644 --- a/TINetworking/Sources/Parameters/ParameterEncoding.swift +++ b/TINetworking/Sources/Parameters/ParameterEncoding.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + protocol ParameterEncoding { associatedtype Location: ParameterLocation associatedtype Result diff --git a/TINetworking/Sources/Parameters/ParameterLocation.swift b/TINetworking/Sources/Parameters/ParameterLocation.swift index 92e0d943..0fe68c32 100644 --- a/TINetworking/Sources/Parameters/ParameterLocation.swift +++ b/TINetworking/Sources/Parameters/ParameterLocation.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + public protocol ParameterLocation {} public struct LocationQuery: ParameterLocation {} diff --git a/TINetworking/Sources/Request/Request.swift b/TINetworking/Sources/Request/Request.swift index 3949c9cb..d4b88b14 100644 --- a/TINetworking/Sources/Request/Request.swift +++ b/TINetworking/Sources/Request/Request.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Alamofire public struct Request { diff --git a/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift b/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift index ffa29c19..a447c7ef 100644 --- a/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift +++ b/TINetworking/Sources/Response/MimeTypeUnsupportedError.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + open class MimeTypeUnsupportedError: Error, CustomDebugStringConvertible { public let mimeType: String? diff --git a/TINetworking/Sources/Response/ResponseType+Decoding.swift b/TINetworking/Sources/Response/ResponseType+Decoding.swift index b1ef2228..ad2a0499 100644 --- a/TINetworking/Sources/Response/ResponseType+Decoding.swift +++ b/TINetworking/Sources/Response/ResponseType+Decoding.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation import TISwiftUtils diff --git a/TINetworking/Sources/Response/ResponseType.swift b/TINetworking/Sources/Response/ResponseType.swift index 0e45359c..d6980445 100644 --- a/TINetworking/Sources/Response/ResponseType.swift +++ b/TINetworking/Sources/Response/ResponseType.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation public protocol ResponseType { diff --git a/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift b/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift index 3563dcc4..844e9044 100644 --- a/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift +++ b/TINetworking/Sources/Response/StatusCodeMimeTypePairUnsupportedError.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + open class StatusCodeMimeTypePairUnsupportedError: MimeTypeUnsupportedError { public let statusCode: Int diff --git a/TINetworking/Sources/Server.swift b/TINetworking/Sources/Server.swift index facbe7c9..e05db673 100644 --- a/TINetworking/Sources/Server.swift +++ b/TINetworking/Sources/Server.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation private enum Scheme: String { diff --git a/TINetworking/Sources/SessionFactory.swift b/TINetworking/Sources/SessionFactory.swift index 816382f5..d12aff10 100644 --- a/TINetworking/Sources/SessionFactory.swift +++ b/TINetworking/Sources/SessionFactory.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation import Alamofire diff --git a/TINetworking/Sources/String+URLExtensions.swift b/TINetworking/Sources/String+URLExtensions.swift index 0d722e85..e152ba5a 100644 --- a/TINetworking/Sources/String+URLExtensions.swift +++ b/TINetworking/Sources/String+URLExtensions.swift @@ -1,3 +1,25 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + import Foundation public extension String { diff --git a/TINetworking/Sources/Typealiases.swift b/TINetworking/Sources/Typealiases.swift index 308efd25..6adf2891 100644 --- a/TINetworking/Sources/Typealiases.swift +++ b/TINetworking/Sources/Typealiases.swift @@ -1 +1,23 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + public typealias KeyValueTuple = (key: K, value: V) From 4b818afa859b8ba53a344c7beab82e33b6c8e65d Mon Sep 17 00:00:00 2001 From: Ivan Smolin Date: Mon, 27 Sep 2021 10:55:55 +0300 Subject: [PATCH 11/11] refactor: fix code review notes --- .../BodyContent/ApplicationJsonBodyContent.swift | 2 ++ .../Sources/Mapping/BodyContent/EmptyBodyContent.swift | 3 +++ .../ApplicationJsonResponseContent.swift | 2 ++ .../Mapping/ResponseContent/MapResponseContent.swift | 9 +++++---- .../ResponseContent/TextPlainResponseContent.swift | 10 ++++------ .../Parameters/Encoding/PathParameterEncoding.swift | 2 ++ .../Encoding/QueryStringParameterEncoding.swift | 3 +++ .../Sources/Parameters/ParameterEncoding.swift | 2 +- 8 files changed, 22 insertions(+), 11 deletions(-) diff --git a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift index f517c503..a99145eb 100644 --- a/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift +++ b/TINetworking/Sources/Mapping/BodyContent/ApplicationJsonBodyContent.swift @@ -42,6 +42,8 @@ open class ApplicationJsonBodyContent: BaseContent, BodyContent { super.init(mediaTypeName: CommonMediaTypes.applicationJson.rawValue) } + // MARK: - BodyContent + public func encodeBody() throws -> Data { try encodingClosure() } diff --git a/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift index 23b5593e..faed4a9c 100644 --- a/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift +++ b/TINetworking/Sources/Mapping/BodyContent/EmptyBodyContent.swift @@ -23,6 +23,9 @@ import Foundation public final class EmptyBodyContent: BaseContent, BodyContent { + + // MARK: - BodyContent + public func encodeBody() throws -> Data { Data() } diff --git a/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift index be01234a..37a6497f 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/ApplicationJsonResponseContent.swift @@ -31,6 +31,8 @@ open class ApplicationJsonResponseContent: BaseContent, Respon super.init(mediaTypeName: CommonMediaTypes.applicationJson.rawValue) } + // MARK: - ResponseContent + public func decodeResponse(data: Data) throws -> Model { try jsonDecoder.decode(Model.self, from: data) } diff --git a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift index f61b983e..7e38fabb 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/MapResponseContent.swift @@ -23,18 +23,19 @@ import Foundation import TISwiftUtils -public struct MapResponseContent: ResponseContent { +public final class MapResponseContent: BaseContent, ResponseContent { private let decodeClosure: ThrowableClosure - public let mediaTypeName: String - public init(responseContent: C, transform: @escaping Closure) { - mediaTypeName = responseContent.mediaTypeName decodeClosure = { transform(try responseContent.decodeResponse(data: $0)) } + + super.init(mediaTypeName: responseContent.mediaTypeName) } + // MARK: - ResponseContent + public func decodeResponse(data: Data) throws -> Model { try decodeClosure(data) } diff --git a/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift index 16146104..c26cd2ff 100644 --- a/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift +++ b/TINetworking/Sources/Mapping/ResponseContent/TextPlainResponseContent.swift @@ -22,20 +22,18 @@ import Foundation -public struct TextPlainResponseContent: ResponseContent { - struct StringDecodingError: Error { +public final class TextPlainResponseContent: BaseContent, ResponseContent { + public struct StringDecodingError: Error { let data: Data let encoding: String.Encoding } private let encoding: String.Encoding - // MARK: - Content - - public let mediaTypeName = CommonMediaTypes.textPlain.rawValue - public init(encoding: String.Encoding = .utf8) { self.encoding = encoding + + super.init(mediaTypeName: CommonMediaTypes.textPlain.rawValue) } // MARK: - ResponseContent diff --git a/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift index 4bd1148c..f11c3da5 100644 --- a/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift +++ b/TINetworking/Sources/Parameters/Encoding/PathParameterEncoding.swift @@ -27,6 +27,8 @@ open class PathParameterEncoding: BaseUrlParameterEncoding, ParameterEncoding { self.templateUrl = templateUrl } + // MARK: - ParameterEncoding + open func encode(parameters: [String: Parameter]) -> String { .render(template: templateUrl, using: encode(parameters: parameters)) } diff --git a/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift b/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift index 8b7353ff..7931e26c 100644 --- a/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift +++ b/TINetworking/Sources/Parameters/Encoding/QueryStringParameterEncoding.swift @@ -21,6 +21,9 @@ // open class QueryStringParameterEncoding: BaseUrlParameterEncoding, ParameterEncoding { + + // MARK: - ParameterEncoding + open func encode(parameters: [String: Parameter]) -> [String: Any] { let includedKeys = Set(super.encode(parameters: parameters).map { $0.key }) diff --git a/TINetworking/Sources/Parameters/ParameterEncoding.swift b/TINetworking/Sources/Parameters/ParameterEncoding.swift index 2cc471c2..16f69eba 100644 --- a/TINetworking/Sources/Parameters/ParameterEncoding.swift +++ b/TINetworking/Sources/Parameters/ParameterEncoding.swift @@ -25,4 +25,4 @@ protocol ParameterEncoding { associatedtype Result func encode(parameters: [String: Parameter]) -> Result -} \ No newline at end of file +}