Skip to content

Commit

Permalink
Merge pull request #26 from joselinoneto/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
joselinoneto authored May 30, 2023
2 parents 4fe2e38 + 02f2cc8 commit 083f79a
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 63 deletions.

This file was deleted.

36 changes: 31 additions & 5 deletions Sources/ToolboxAPIClient/BaseNetworkWorker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
import Foundation
import Combine

public class BaseNetworkWorker<T> where T: Codable {
public class BaseNetworkWorker<T, E> 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
Expand Down Expand Up @@ -52,6 +54,9 @@ public class BaseNetworkWorker<T> 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)

Expand All @@ -67,12 +72,33 @@ public class BaseNetworkWorker<T> 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)
}
}
19 changes: 19 additions & 0 deletions Sources/ToolboxAPIClient/Errors.swift
Original file line number Diff line number Diff line change
@@ -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)
}
23 changes: 23 additions & 0 deletions Tests/ToolboxAPIClientTests/Network/Story/Errors/Errors.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,21 @@ import Foundation
import ToolboxAPIClient

public class LoginManagerAPI: LoginRequestable {
public func notFound() async throws {
_ = try await BaseNetworkWorker<UserDto, APIReason>(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<LoginDto>(target: LoginTarget.login).urlRequest(contentBody: login)
return try await BaseNetworkWorker<LoginDto, APIReason>(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<LoginDto>(target: LoginTarget.createUser).urlRequest(contentBody: login)
return try await BaseNetworkWorker<LoginDto, APIReason>(target: LoginTarget.createUser).urlRequest(contentBody: login)
}

public func me() async throws -> UserDto? {
try await BaseNetworkWorker<UserDto>(target: LoginTarget.me).urlRequest()
try await BaseNetworkWorker<UserDto, APIReason>(target: LoginTarget.me).urlRequest()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -40,6 +42,8 @@ extension LoginTarget: TargetType {
return "login"
case .me:
return "me"
case .notFound:
return "notfound"
}
}

Expand All @@ -51,6 +55,8 @@ extension LoginTarget: TargetType {
return .post
case .me:
return .get
case .notFound:
return .get
}
}

Expand Down
48 changes: 45 additions & 3 deletions Tests/ToolboxAPIClientTests/Tests/app_zeneto_api_moduleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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!

Expand Down Expand Up @@ -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)
}
}

Expand Down

0 comments on commit 083f79a

Please sign in to comment.