diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ToolboxAPIClientTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ToolboxAPIClientTests.xcscheme
deleted file mode 100644
index f965e5f..0000000
--- a/.swiftpm/xcode/xcshareddata/xcschemes/ToolboxAPIClientTests.xcscheme
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Sources/ToolboxAPIClient/BaseNetworkWorker.swift b/Sources/ToolboxAPIClient/BaseNetworkWorker.swift
index 5e558f4..a4d1714 100644
--- a/Sources/ToolboxAPIClient/BaseNetworkWorker.swift
+++ b/Sources/ToolboxAPIClient/BaseNetworkWorker.swift
@@ -8,8 +8,10 @@
import Foundation
import Combine
-public class BaseNetworkWorker where T: Codable {
+public class BaseNetworkWorker where T: Codable, E: Codable {
private var targetType: TargetType
+ private let validStatusCode: [Int] = [200, 201]
+ private let invalidStatusCode: [Int] = [401, 404]
public init(target: TargetType) {
self.targetType = target
@@ -52,6 +54,9 @@ public class BaseNetworkWorker where T: Codable {
}
public func urlRequest(contentBody: T? = nil) async throws -> T? {
+ // Decoder
+ let decoder = JSONDecoder()
+
// set route with base and path
var urlRequest = URLRequest(url: finalUrl)
@@ -67,12 +72,33 @@ public class BaseNetworkWorker where T: Codable {
if let httpBody = contentBody {
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
- let data = try? jsonEncoder.encode(httpBody)
- urlRequest.httpBody = data
+ let bodyData = try? jsonEncoder.encode(httpBody)
+ urlRequest.httpBody = bodyData
+ }
+
+ let (data, response) = try await URLSession.shared.data(for: urlRequest)
+
+ guard let httpResponse = response as? HTTPURLResponse else {
+ throw APIErrors.invalidResponse
+ }
+
+ guard !invalidStatusCode.contains(httpResponse.statusCode) else {
+ switch httpResponse.statusCode {
+ case 401:
+ throw APIErrors.authenticationError
+ case 404:
+ throw APIErrors.notFound
+ default:
+ let error: E = try decoder.decode(E.self, from: data)
+ throw APIErrors.serverError(error: error)
+ }
+ }
+
+ guard validStatusCode.contains(httpResponse.statusCode) else {
+ let error: E = try decoder.decode(E.self, from: data)
+ throw APIErrors.serverError(error: error)
}
- let (data, _) = try await URLSession.shared.data(for: urlRequest)
- let decoder = JSONDecoder()
return try decoder.decode(T?.self, from: data)
}
}
diff --git a/Sources/ToolboxAPIClient/Errors.swift b/Sources/ToolboxAPIClient/Errors.swift
new file mode 100644
index 0000000..adade91
--- /dev/null
+++ b/Sources/ToolboxAPIClient/Errors.swift
@@ -0,0 +1,19 @@
+//
+// File.swift
+//
+//
+// Created by José Neto on 12/03/2023.
+//
+
+import Foundation
+
+public enum APIErrors: Error, Equatable {
+ public static func == (lhs: APIErrors, rhs: APIErrors) -> Bool {
+ lhs.localizedDescription == rhs.localizedDescription
+ }
+
+ case notFound
+ case invalidResponse
+ case authenticationError
+ case serverError(error: Codable)
+}
diff --git a/Tests/ToolboxAPIClientTests/Network/Story/Errors/Errors.swift b/Tests/ToolboxAPIClientTests/Network/Story/Errors/Errors.swift
new file mode 100644
index 0000000..a83e69a
--- /dev/null
+++ b/Tests/ToolboxAPIClientTests/Network/Story/Errors/Errors.swift
@@ -0,0 +1,23 @@
+//
+// File.swift
+//
+//
+// Created by José Neto on 12/03/2023.
+//
+
+import Foundation
+
+struct APIReason: Codable {
+ let error: Bool
+ let reason: String
+}
+
+class APIError: Codable {
+ let errorCode: Int
+ let reason: APIReason
+
+ init(errorCode: String, reason: APIReason) {
+ self.errorCode = Int(errorCode) ?? 0
+ self.reason = reason
+ }
+}
diff --git a/Tests/ToolboxAPIClientTests/Network/Story/Manager/LoginManagerAPI.swift b/Tests/ToolboxAPIClientTests/Network/Story/Manager/LoginManagerAPI.swift
index c988179..9cae54d 100644
--- a/Tests/ToolboxAPIClientTests/Network/Story/Manager/LoginManagerAPI.swift
+++ b/Tests/ToolboxAPIClientTests/Network/Story/Manager/LoginManagerAPI.swift
@@ -9,17 +9,21 @@ import Foundation
import ToolboxAPIClient
public class LoginManagerAPI: LoginRequestable {
+ public func notFound() async throws {
+ _ = try await BaseNetworkWorker(target: LoginTarget.notFound).urlRequest()
+ }
+
public func login(email: String, password: String) async throws -> LoginDto? {
let login: LoginDto = LoginDto(email: email, password: password, token: nil)
- return try await BaseNetworkWorker(target: LoginTarget.login).urlRequest(contentBody: login)
+ return try await BaseNetworkWorker(target: LoginTarget.login).urlRequest(contentBody: login)
}
public func createUser(email: String, password: String) async throws -> LoginDto? {
let login: LoginDto = LoginDto(email: email, password: password, token: nil)
- return try await BaseNetworkWorker(target: LoginTarget.createUser).urlRequest(contentBody: login)
+ return try await BaseNetworkWorker(target: LoginTarget.createUser).urlRequest(contentBody: login)
}
public func me() async throws -> UserDto? {
- try await BaseNetworkWorker(target: LoginTarget.me).urlRequest()
+ try await BaseNetworkWorker(target: LoginTarget.me).urlRequest()
}
}
diff --git a/Tests/ToolboxAPIClientTests/Network/Story/Targets/LoginTarget.swift b/Tests/ToolboxAPIClientTests/Network/Story/Targets/LoginTarget.swift
index 147f7cf..6e1da57 100644
--- a/Tests/ToolboxAPIClientTests/Network/Story/Targets/LoginTarget.swift
+++ b/Tests/ToolboxAPIClientTests/Network/Story/Targets/LoginTarget.swift
@@ -12,12 +12,14 @@ public protocol LoginRequestable {
func createUser(email: String, password: String) async throws -> LoginDto?
func login(email: String, password: String) async throws -> LoginDto?
func me() async throws -> UserDto?
+ func notFound() async throws
}
public enum LoginTarget {
case createUser
case login
case me
+ case notFound
}
extension LoginTarget: TargetType {
@@ -40,6 +42,8 @@ extension LoginTarget: TargetType {
return "login"
case .me:
return "me"
+ case .notFound:
+ return "notfound"
}
}
@@ -51,6 +55,8 @@ extension LoginTarget: TargetType {
return .post
case .me:
return .get
+ case .notFound:
+ return .get
}
}
diff --git a/Tests/ToolboxAPIClientTests/Tests/app_zeneto_api_moduleTests.swift b/Tests/ToolboxAPIClientTests/Tests/app_zeneto_api_moduleTests.swift
index b849c84..13c3ff2 100644
--- a/Tests/ToolboxAPIClientTests/Tests/app_zeneto_api_moduleTests.swift
+++ b/Tests/ToolboxAPIClientTests/Tests/app_zeneto_api_moduleTests.swift
@@ -11,8 +11,8 @@ import Combine
@testable import ToolboxAPIClient
class app_zeneto_api_moduleTests: XCTestCase {
- let expectation = XCTestExpectation(description: "CREATE AND LOGIN")
- let timeout: TimeInterval = 5.0
+ var expectation = XCTestExpectation(description: "CREATE AND LOGIN")
+ let timeout: TimeInterval = 15.0
var email: String!
var password: String!
@@ -54,7 +54,49 @@ class app_zeneto_api_moduleTests: XCTestCase {
let me = try await userWorker.me()
XCTAssertNotNil(me)
XCTAssertEqual(email, me?.email)
-
+
+ defaults.removeObject(forKey: "token")
+ defaults.synchronize()
+ }
+
+ func testErrorLoginUser() throws {
+ let userWorker = LoginManagerAPI()
+ expectation = expectation(description: "error login")
+ // login user
+ Task {
+ do {
+ _ = try await userWorker.me()
+ } catch {
+ print(error.localizedDescription)
+ let exception = error as? APIErrors
+ XCTAssertNotNil(exception)
+ XCTAssertEqual(exception, APIErrors.authenticationError)
+ }
+
+ expectation.fulfill()
+ }
+
+ waitForExpectations(timeout: timeout)
+ }
+
+ func testNotFound() throws {
+ let userWorker = LoginManagerAPI()
+ expectation = expectation(description: "error login")
+ // login user
+ Task {
+ do {
+ _ = try await userWorker.notFound()
+ } catch {
+ print(error.localizedDescription)
+ let exception = error as? APIErrors
+ XCTAssertNotNil(exception)
+ XCTAssertEqual(exception, APIErrors.notFound)
+ }
+
+ expectation.fulfill()
+ }
+
+ waitForExpectations(timeout: timeout)
}
}