diff --git a/.travis.yml b/.travis.yml index f45c78d..0094170 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,15 +11,6 @@ sudo: required jobs: include: - - os: linux - services: docker - env: DOCKER_IMAGE=swift:4.0.3 SWIFT_SNAPSHOT=4.0.3 - - os: linux - services: docker - env: DOCKER_IMAGE=swift:4.1.3 SWIFT_SNAPSHOT=4.1.3 - - os: linux - services: docker - env: DOCKER_IMAGE=swift:4.2.4 SWIFT_SNAPSHOT=4.2.4 - os: linux services: docker env: DOCKER_IMAGE=swift:5.0.3-xenial SWIFT_SNAPSHOT=5.0.3 @@ -29,15 +20,6 @@ jobs: - os: linux services: docker env: DOCKER_IMAGE=swift:5.1 SWIFT_SNAPSHOT=$SWIFT_DEVELOPMENT_SNAPSHOT - - os: osx - osx_image: xcode9.2 - env: SWIFT_SNAPSHOT=4.0.3 - - os: osx - osx_image: xcode9.4 - env: SWIFT_SNAPSHOT=4.1.2 - - os: osx - osx_image: xcode10.1 - env: SWIFT_SNAPSHOT=4.2.1 - os: osx osx_image: xcode10.2 env: SWIFT_SNAPSHOT=5.0.1 JAZZY_ELIGIBLE=true diff --git a/Package.swift b/Package.swift index 3538e82..1b93666 100644 --- a/Package.swift +++ b/Package.swift @@ -30,7 +30,7 @@ let package = Package( ], dependencies: [ // Dependencies declare other packages that this package depends on. - .package(url: "https://github.com/IBM-Swift/SwiftyRequest.git", from: "2.0.0"), + .package(url: "https://github.com/IBM-Swift/SwiftyRequest.git", from: "3.0.0"), .package(url: "https://github.com/IBM-Swift/KituraContracts.git", from: "1.0.0"), ], targets: [ diff --git a/Package@swift-4.swift b/Package@swift-4.swift deleted file mode 100644 index 3dc9218..0000000 --- a/Package@swift-4.swift +++ /dev/null @@ -1,48 +0,0 @@ -// swift-tools-version:4.0 -// The swift-tools-version declares the minimum version of Swift required to build this package. -/* - * Copyright IBM Corporation 2017 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import PackageDescription - -let package = Package( - name: "KituraKit", - products: [ - // Products define the executables and libraries produced by a package, and make them visible to other packages. - .library( - name: "KituraKit", - targets: ["KituraKit"] - ), - ], - dependencies: [ - // Dependencies declare other packages that this package depends on. - .package(url: "https://github.com/IBM-Swift/SwiftyRequest.git", from: "2.0.0"), - .package(url: "https://github.com/IBM-Swift/KituraContracts.git", from: "1.0.0"), - ], - targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages which this package depends on. - // CRUD and CRUD tests removed until the files compile - .target( - name: "KituraKit", - dependencies: ["KituraContracts", "SwiftyRequest"] - ), - .testTarget( - name: "KituraKitTests", - dependencies: ["KituraContracts", "KituraKit"] - ), - ] -) diff --git a/Sources/KituraKit/Client.swift b/Sources/KituraKit/Client.swift index 07d0d7f..1ebad5d 100644 --- a/Sources/KituraKit/Client.swift +++ b/Sources/KituraKit/Client.swift @@ -96,11 +96,7 @@ public class KituraKit { /// - clientCertificate: Pass in `ClientCertificate` with the certificate name and path to use client certificates for 2-way SSL public init(baseURL: URL, containsSelfSignedCert: Bool = false, clientCertificate: ClientCertificate? = nil) { self.baseURL = baseURL - if let clientCertificate = clientCertificate { - self.clientCertificate = SwiftyRequest.ClientCertificate(name: clientCertificate.name, path: clientCertificate.path) - } else { - self.clientCertificate = nil - } + self.clientCertificate = clientCertificate self.containsSelfSignedCert = containsSelfSignedCert } @@ -141,7 +137,7 @@ public class KituraKit { public func get(_ route: String, credentials: ClientCredentials? = nil, respondWith: @escaping CodableResultClosure) { let credentials = (credentials ?? defaultCredentials) let url = baseURL.appendingPathComponent(route) - let request = RestRequest(url: url.absoluteString, containsSelfSignedCert: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) + let request = RestRequest(url: url.absoluteString, insecure: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) request.headerParameters = credentials?.getHeaders() ?? [:] request.acceptType = mediaType request.handle(decoder: decoder, respondWith) @@ -167,7 +163,7 @@ public class KituraKit { public func get(_ route: String, identifier: Identifier, credentials: ClientCredentials? = nil, respondWith: @escaping CodableResultClosure) { let credentials = (credentials ?? defaultCredentials) let url = baseURL.appendingPathComponent(route).appendingPathComponent(identifier.value) - let request = RestRequest(url: url.absoluteString, containsSelfSignedCert: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) + let request = RestRequest(url: url.absoluteString, insecure: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) request.headerParameters = credentials?.getHeaders() ?? [:] request.acceptType = mediaType request.handle(decoder: decoder, respondWith) @@ -193,7 +189,7 @@ public class KituraKit { let credentials = (credentials ?? defaultCredentials) let url = baseURL.appendingPathComponent(route) let encoded = try? encoder.encode(data) - let request = RestRequest(method: .post, url: url.absoluteString, containsSelfSignedCert: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) + let request = RestRequest(method: .post, url: url.absoluteString, insecure: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) request.messageBody = encoded request.headerParameters = credentials?.getHeaders() ?? [:] request.acceptType = mediaType @@ -221,16 +217,16 @@ public class KituraKit { let credentials = (credentials ?? defaultCredentials) let url = baseURL.appendingPathComponent(route) let encoded = try? encoder.encode(data) - let request = RestRequest(method: .post, url: url.absoluteString, containsSelfSignedCert: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) + let request = RestRequest(method: .post, url: url.absoluteString, insecure: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) request.messageBody = encoded request.headerParameters = credentials?.getHeaders() ?? [:] request.acceptType = mediaType request.contentType = mediaType - request.responseData { response in - switch response.result { - case .success(let data): - guard let item: O = try? self.decoder.decode(O.self, from: data), - let locationHeader = response.response?.allHeaderFields["Location"] as? String, + request.responseData { result in + switch result { + case .success(let response): + guard let item: O = try? self.decoder.decode(O.self, from: response.body), + let locationHeader = response.headers["Location"].first, let id = try? Id.init(value: locationHeader) else { respondWith(nil, nil, RequestError.clientDeserializationError) @@ -239,7 +235,7 @@ public class KituraKit { respondWith(id, item, nil) case .failure(let error): Log.error("POST failure: \(error)") - respondWith(nil, nil, constructRequestError(from: error, data: response.data)) + respondWith(nil, nil, constructRequestError(from: error, data: error.responseData)) } } } @@ -267,7 +263,7 @@ public class KituraKit { let credentials = (credentials ?? defaultCredentials) let url = baseURL.appendingPathComponent(route).appendingPathComponent(identifier.value) let encoded = try? encoder.encode(data) - let request = RestRequest(method: .put, url: url.absoluteString, containsSelfSignedCert: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) + let request = RestRequest(method: .put, url: url.absoluteString, insecure: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) request.messageBody = encoded request.headerParameters = credentials?.getHeaders() ?? [:] request.acceptType = mediaType @@ -304,7 +300,7 @@ public class KituraKit { let credentials = (credentials ?? defaultCredentials) let url = baseURL.appendingPathComponent(route).appendingPathComponent(identifier.value) let encoded = try? encoder.encode(data) - let request = RestRequest(method: .patch, url: url.absoluteString, containsSelfSignedCert: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) + let request = RestRequest(method: .patch, url: url.absoluteString, insecure: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) request.messageBody = encoded request.headerParameters = credentials?.getHeaders() ?? [:] request.acceptType = mediaType @@ -326,7 +322,7 @@ public class KituraKit { public func delete(_ route: String, credentials: ClientCredentials? = nil, respondWith: @escaping ResultClosure) { let credentials = (credentials ?? defaultCredentials) let url = baseURL.appendingPathComponent(route) - let request = RestRequest(method: .delete, url: url.absoluteString, containsSelfSignedCert: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) + let request = RestRequest(method: .delete, url: url.absoluteString, insecure: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) request.headerParameters = credentials?.getHeaders() ?? [:] request.acceptType = mediaType request.contentType = mediaType @@ -348,7 +344,7 @@ public class KituraKit { public func delete(_ route: String, identifier: Identifier, credentials: ClientCredentials? = nil, respondWith: @escaping ResultClosure) { let credentials = (credentials ?? defaultCredentials) let url = baseURL.appendingPathComponent(route).appendingPathComponent(identifier.value) - let request = RestRequest(method: .delete, url: url.absoluteString, containsSelfSignedCert: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) + let request = RestRequest(method: .delete, url: url.absoluteString, insecure: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) request.headerParameters = credentials?.getHeaders() ?? [:] request.acceptType = mediaType request.contentType = mediaType @@ -382,7 +378,7 @@ public class KituraKit { respondWith(nil, .clientSerializationError) return } - let request = RestRequest(method: .get, url: baseURL.appendingPathComponent(route).absoluteString, containsSelfSignedCert: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) + let request = RestRequest(method: .get, url: baseURL.appendingPathComponent(route).absoluteString, insecure: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) request.headerParameters = credentials?.getHeaders() ?? [:] request.acceptType = mediaType request.contentType = mediaType @@ -413,7 +409,7 @@ public class KituraKit { respondWith(.clientSerializationError) return } - let request = RestRequest(method: .delete, url: baseURL.appendingPathComponent(route).absoluteString, containsSelfSignedCert: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) + let request = RestRequest(method: .delete, url: baseURL.appendingPathComponent(route).absoluteString, insecure: self.containsSelfSignedCert, clientCertificate: self.clientCertificate) request.headerParameters = credentials?.getHeaders() ?? [:] request.acceptType = mediaType request.contentType = mediaType @@ -426,25 +422,25 @@ extension RestRequest { /// Helper method to handle the given request for CodableArrayResultClosures and CodableResultClosures fileprivate func handle(decoder: BodyDecoder, _ respondWith: @escaping (O?, RequestError?) -> (), queryItems: [URLQueryItem]? = nil) { - self.responseData(queryItems: queryItems) { response in - switch response.result { - case .success(let data) : - self.defaultCodableHandler(decoder: decoder, data, respondWith: respondWith) + self.responseData(queryItems: queryItems) { result in + switch result { + case .success(let response): + self.defaultCodableHandler(decoder: decoder, response.body, respondWith: respondWith) case .failure(let error): - self.defaultErrorHandler(error, data: response.data, respondWith: respondWith) + self.defaultErrorHandler(error, data: error.responseData, respondWith: respondWith) } } } /// Helper method to handle the given delete request fileprivate func handleDelete(_ respondWith: @escaping (RequestError?) -> (), queryItems: [URLQueryItem]? = nil) { - self.responseData(queryItems: queryItems) { response in - switch response.result { + self.responseVoid(queryItems: queryItems) { result in + switch result { case .success: respondWith(nil) case .failure(let error): Log.error("DELETE failure: \(error)") - respondWith(constructRequestError(from: error, data: response.data)) + respondWith(constructRequestError(from: error, data: error.responseData)) } } } diff --git a/Sources/KituraKit/ClientCertificate.swift b/Sources/KituraKit/ClientCertificate.swift index 88a45a8..4bd0fcb 100644 --- a/Sources/KituraKit/ClientCertificate.swift +++ b/Sources/KituraKit/ClientCertificate.swift @@ -1,5 +1,5 @@ /* - * Copyright IBM Corporation 2018 + * Copyright IBM Corporation 2019 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,16 +14,7 @@ * limitations under the License. */ -/// Struct to store client certificate name and path -public struct ClientCertificate { - /// The name for the client certificate - public let name: String - /// The path to the client certificate - public let path: String +import SwiftyRequest - /// Initialize a `ClientCertificate` instance - public init(name: String, path: String) { - self.name = name - self.path = path - } -} +/// An alias of `SwiftyRequest.ClientCertificate`, so that you do not have to import SwiftyRequest directly. +public typealias ClientCertificate = SwiftyRequest.ClientCertificate diff --git a/Sources/KituraKit/RequestErrorExtension.swift b/Sources/KituraKit/RequestErrorExtension.swift index 8488d55..2e8bf1f 100644 --- a/Sources/KituraKit/RequestErrorExtension.swift +++ b/Sources/KituraKit/RequestErrorExtension.swift @@ -53,6 +53,9 @@ extension RequestError { /// An HTTP 608 invalid substitution error public static var clientInvalidSubstitution = RequestError(clientErrorCode: 608, clientErrorDescription: "An invalid substitution error occurred. Please ensure that the data being substituted is correct.") + + /// An HTTP 609 encoding error + public static var clientDecodingError = RequestError(clientErrorCode: 609, clientErrorDescription: "A decoding error occurred. Please ensure that the types and format of the data being received is correct.") } /// An extension to Kitura RequestErrors with additional error codes specifically for the client. @@ -62,13 +65,23 @@ extension RequestError { /// - Parameter restError: The custom error type for the client. public init(restError: RestError) { switch restError { - case .erroredResponseStatus(let code): self = RequestError(httpCode: code) case .noData: self = .clientNoData case .serializationError: self = .clientSerializationError case .encodingError: self = .clientEncodingError + case .decodingError: self = .clientDecodingError case .fileManagerError: self = .clientFileManagerError case .invalidFile: self = .clientInvalidFile case .invalidSubstitution: self = .clientInvalidSubstitution + case .invalidURL: fallthrough // Will not occur: Client can only be initialized with a valid URL + case .downloadError: fallthrough // Will not occur: API is not used by KituraKit + case .errorStatusCode: fallthrough + default: + // All other cases: + if let response = restError.response { + self = RequestError(httpCode: Int(response.status.code)) + } else { + self = RequestError(rawValue: 0, reason: "Error: No response was received by the client") + } } } }