Skip to content

Commit

Permalink
Merge pull request #154 from okta/ognidets-OKTA-449793-Review-error-h…
Browse files Browse the repository at this point in the history
…andling

Improve error handling
  • Loading branch information
oleggnidets-okta authored Dec 13, 2021
2 parents 2ce925e + a0448ac commit e2c6e12
Show file tree
Hide file tree
Showing 15 changed files with 59 additions and 53 deletions.
24 changes: 12 additions & 12 deletions Source/OktaError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@

import Foundation

public enum OktaError: Error {
case errorBuildingURLRequest
public enum OktaError: LocalizedError {
case errorBuildingURLRequest(String)
case connectionError(Error)
case emptyServerResponse
case invalidResponse
case invalidResponse(String)
case responseSerializationError(Error, Data)
case serverRespondedWithError(OktaAPIErrorResponse)
case unexpectedResponse
Expand All @@ -30,14 +30,14 @@ public enum OktaError: Error {
public extension OktaError {
var description: String {
switch self {
case .errorBuildingURLRequest:
return "Error building URL request"
case let .errorBuildingURLRequest(reason):
return "Error building URL request.\nReason Failure: \(reason)."
case .connectionError(let error):
return "Connection error (\(error.localizedDescription))"
case .emptyServerResponse:
return "Empty server response"
case .invalidResponse:
return "Invalid server response"
case let .invalidResponse(error):
return "Invalid server response: \(error)"
case .responseSerializationError(let error, _):
return "Response serialization error (\(error.localizedDescription))"
case .serverRespondedWithError(let error):
Expand All @@ -58,14 +58,14 @@ public extension OktaError {
return "Another request is in progress"
case .unknownStatus:
return "Received state is unknown"
case .internalError:
return "Internal error"
case .invalidParameters:
return "Invalid parameters"
case let .internalError(error):
return "Internal error: \(error)"
case let .invalidParameters(error):
return "Invalid parameters: \(error)"
}
}

var localizedDescription: String {
return NSLocalizedString(self.description, comment: "")
NSLocalizedString(description, comment: "")
}
}
32 changes: 19 additions & 13 deletions Source/RestAPI/OktaAPIRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,17 @@ public class OktaAPIRequest {
case get, post, put, delete, options
}

public func buildRequest() -> URLRequest? {
public func buildRequest() throws -> URLRequest {
guard var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: true) else {
return nil
throw OktaError.errorBuildingURLRequest("Cannot parse URL components")
}

if let path = path {
components.path = path
}
components.queryItems = urlParams?.map { URLQueryItem(name: $0.key, value: $0.value) }
guard let url = components.url else {
return nil
throw OktaError.errorBuildingURLRequest("Cannot create URL from components")
}

var urlRequest = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 60)
Expand All @@ -73,27 +74,32 @@ public class OktaAPIRequest {

if let bodyParams = bodyParams {
guard let body = try? JSONSerialization.data(withJSONObject: bodyParams, options: []) else {
return nil
throw OktaError.errorBuildingURLRequest("Cannot parse `bodyParams` to JSON data.")
}

urlRequest.httpBody = body
}

return urlRequest
}

public func run() {
guard isCancelled == false else {
return
}
guard let urlRequest = buildRequest() else {
completion(self, .error(.errorBuildingURLRequest))
if isCancelled {
return
}

do {
let urlRequest = try buildRequest()

if let httpClient = httpClient {
performRequest(urlRequest, withHTTPClient: httpClient)
} else {
performRequest(urlRequest, withURLSession: urlSession)
if let httpClient = httpClient {
performRequest(urlRequest, withHTTPClient: httpClient)
} else {
performRequest(urlRequest, withURLSession: urlSession)
}
} catch let oktaError as OktaError {
completion(self, .error(oktaError))
} catch {
completion(self, .error(.errorBuildingURLRequest("Unknown error")))
}
}

Expand Down
2 changes: 1 addition & 1 deletion Source/Statuses/OktaAuthStatePasswordReset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ open class OktaAuthStatusPasswordReset : OktaAuthStatus {

public override init(currentState: OktaAuthStatus, model: OktaAPISuccessResponse) throws {
guard let stateToken = model.stateToken else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("State token is missed")
}
self.stateToken = stateToken
if let policy = model.embedded?.policy {
Expand Down
4 changes: 2 additions & 2 deletions Source/Statuses/OktaAuthStatus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ open class OktaAuthStatus {
}

guard let stateToken = model.stateToken else {
onError(.invalidResponse)
onError(.invalidResponse("State token is missed"))
return
}

Expand Down Expand Up @@ -106,7 +106,7 @@ open class OktaAuthStatus {
return
}
guard let stateToken = model.stateToken else {
onError?(.invalidResponse)
onError?(.invalidResponse("State token is missed"))
return
}

Expand Down
4 changes: 2 additions & 2 deletions Source/Statuses/OktaAuthStatusFactorChallenge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ open class OktaAuthStatusFactorChallenge : OktaAuthStatus {

public override init(currentState: OktaAuthStatus, model: OktaAPISuccessResponse) throws {
guard let stateToken = model.stateToken else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("State token is missed")
}
guard let factor = model.embedded?.factor else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("Embedded factor is missed")
}
self.stateToken = stateToken
internalFactor = factor
Expand Down
4 changes: 2 additions & 2 deletions Source/Statuses/OktaAuthStatusFactorEnroll.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ open class OktaAuthStatusFactorEnroll : OktaAuthStatus {

public override init(currentState: OktaAuthStatus, model: OktaAPISuccessResponse) throws {
guard let stateToken = model.stateToken else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("State token is missed")
}
guard let factors = model.embedded?.factors else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("Embedded factors are missed")
}
self.stateToken = stateToken
self.factors = factors
Expand Down
6 changes: 3 additions & 3 deletions Source/Statuses/OktaAuthStatusFactorEnrollActivate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ open class OktaAuthStatusFactorEnrollActivate : OktaAuthStatus {

public override init(currentState: OktaAuthStatus, model: OktaAPISuccessResponse) throws {
guard let stateToken = model.stateToken else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("State token is missed")
}
guard let factor = model.embedded?.factor else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("Embedded factor is missed")
}
guard let activateLink = model.links?.next else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("Links are missed")
}
self.stateToken = stateToken
self.internalFactor = factor
Expand Down
4 changes: 2 additions & 2 deletions Source/Statuses/OktaAuthStatusFactorRequired.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ open class OktaAuthStatusFactorRequired : OktaAuthStatus {

public override init(currentState: OktaAuthStatus, model: OktaAPISuccessResponse) throws {
guard let stateToken = model.stateToken else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("State token is missed")
}
guard let factors = model.embedded?.factors else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("Embedded factors are missed")
}
self.stateToken = stateToken
self.factors = factors
Expand Down
2 changes: 1 addition & 1 deletion Source/Statuses/OktaAuthStatusPasswordExpired.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ open class OktaAuthStatusPasswordExpired : OktaAuthStatus {

public override init(currentState: OktaAuthStatus, model: OktaAPISuccessResponse) throws {
guard let stateToken = model.stateToken else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("State token is missed")
}
self.stateToken = stateToken
try super.init(currentState: currentState, model: model)
Expand Down
2 changes: 1 addition & 1 deletion Source/Statuses/OktaAuthStatusPasswordWarning.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ open class OktaAuthStatusPasswordWarning : OktaAuthStatus {

public override init(currentState: OktaAuthStatus, model: OktaAPISuccessResponse) throws {
guard let stateToken = model.stateToken else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("State token is missed")
}
self.stateToken = stateToken
try super.init(currentState: currentState, model: model)
Expand Down
2 changes: 1 addition & 1 deletion Source/Statuses/OktaAuthStatusRecovery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ open class OktaAuthStatusRecovery : OktaAuthStatus {

public override init(currentState: OktaAuthStatus, model: OktaAPISuccessResponse) throws {
guard let stateToken = model.stateToken else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("State token is missed")
}
self.stateToken = stateToken
try super.init(currentState: currentState, model: model)
Expand Down
6 changes: 3 additions & 3 deletions Source/Statuses/OktaAuthStatusRecoveryChallenge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ open class OktaAuthStatusRecoveryChallenge : OktaAuthStatus {
onStatusChange: @escaping (_ newStatus: OktaAuthStatus) -> Void,
onError: @escaping (_ error: OktaError) -> Void) {
guard let stateToken = model.stateToken else {
onError(.invalidResponse)
onError(.invalidResponse("State token is missed"))
return
}
guard canVerify() else {
Expand All @@ -83,7 +83,7 @@ open class OktaAuthStatusRecoveryChallenge : OktaAuthStatus {
onStatusChange: @escaping (_ newStatus: OktaAuthStatus) -> Void,
onError: @escaping (_ error: OktaError) -> Void) {
guard let stateToken = model.stateToken else {
onError(.invalidResponse)
onError(.invalidResponse("State token is missed"))
return
}
guard canVerify() else {
Expand All @@ -107,7 +107,7 @@ open class OktaAuthStatusRecoveryChallenge : OktaAuthStatus {
open func resendFactor(onStatusChange: @escaping (_ newStatus: OktaAuthStatus) -> Void,
onError: @escaping (_ error: OktaError) -> Void) {
guard let stateToken = model.stateToken else {
onError(.invalidResponse)
onError(.invalidResponse("State token is missed"))
return
}
guard canResend() else {
Expand Down
2 changes: 1 addition & 1 deletion Source/Statuses/OktaAuthStatusResponseHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ open class OktaAuthStatusResponseHandler {
open func createAuthStatus(basedOn response: OktaAPISuccessResponse,
and currentStatus: OktaAuthStatus) throws -> OktaAuthStatus {
guard let statusType = response.status else {
throw OktaError.invalidResponse
throw OktaError.invalidResponse("Status is missed")
}

// create concrete status instance
Expand Down
14 changes: 7 additions & 7 deletions Tests/RestAPI/OktaAPIRequestTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class OktaAPIRequestTests : XCTestCase {
req = nil
}

func testSetsHTTPSScheme() {
guard let URLString = req.buildRequest()?.url?.absoluteString else {
func testSetsHTTPSScheme() throws {
guard let URLString = try XCTUnwrap(req.buildRequest()).url?.absoluteString else {
XCTFail("No URL string")
return
}
Expand All @@ -40,7 +40,7 @@ class OktaAPIRequestTests : XCTestCase {
req.path = "/test/path"
req.urlParams = ["param": "value"]

guard let URLString = req.buildRequest()?.url?.absoluteString else {
guard let URLString = try? req.buildRequest().url?.absoluteString else {
XCTFail("No URL string")
return
}
Expand All @@ -49,7 +49,7 @@ class OktaAPIRequestTests : XCTestCase {
}

func testHeaders() {
guard let URLRequest = req.buildRequest() else {
guard let URLRequest = try? req.buildRequest() else {
XCTFail("No URL request")
return
}
Expand All @@ -64,7 +64,7 @@ class OktaAPIRequestTests : XCTestCase {
let value = "HEADER_VALUE"
req.additionalHeaders = [header: value]

guard let URLRequest = req.buildRequest() else {
guard let URLRequest = try? req.buildRequest() else {
XCTFail("No URL request")
return
}
Expand All @@ -75,7 +75,7 @@ class OktaAPIRequestTests : XCTestCase {
func testBodyParams() {
req.bodyParams = ["root_param": [ "nested_param": "value" ]]

guard let URLRequest = req.buildRequest() else {
guard let URLRequest = try? req.buildRequest() else {
XCTFail("No URL request")
return
}
Expand All @@ -92,7 +92,7 @@ class OktaAPIRequestTests : XCTestCase {
func testMethod() {
req.method = .delete

guard let methodString = req.buildRequest()?.httpMethod else {
guard let methodString = try? req.buildRequest().httpMethod else {
XCTFail("No HTTP method")
return
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/Statuses/OktaAuthStatusRecoveryChallengeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class OktaAuthStatusRecoveryChallengeTests: XCTestCase {
},
onError: { error in
XCTAssertEqual(
"Invalid server response",
"Invalid server response: State token is missed",
error.localizedDescription
)
ex.fulfill()
Expand All @@ -59,7 +59,7 @@ class OktaAuthStatusRecoveryChallengeTests: XCTestCase {
},
onError: { error in
XCTAssertEqual(
"Invalid server response",
"Invalid server response: State token is missed",
error.localizedDescription
)
ex.fulfill()
Expand Down

0 comments on commit e2c6e12

Please sign in to comment.