Skip to content

Commit

Permalink
Merge pull request #131 from adessoTurkey/feature/SASU0122-ServiceLay…
Browse files Browse the repository at this point in the history
…erModularization

[SASU-0122] - Service Layer Modularization #124
  • Loading branch information
bahaadesso authored Dec 27, 2023
2 parents e9120ca + 2fbbafd commit cbc596f
Show file tree
Hide file tree
Showing 104 changed files with 1,310 additions and 551 deletions.
8 changes: 8 additions & 0 deletions Projects/NetworkService/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
26 changes: 26 additions & 0 deletions Projects/NetworkService/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "NetworkService",
platforms: [
.iOS(.v16)
],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "NetworkService",
targets: ["NetworkService"]),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "NetworkService"),
.testTarget(
name: "NetworkServiceTests",
dependencies: ["NetworkService"]),
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// NetworkLoader.swift
// SampleAppSwiftUI
//
// Created by Saglam, Fatih on 10.01.2023.
// Copyright © 2023 Adesso Turkey. All rights reserved.
//

import Foundation

public class NetworkLoader: NetworkLoaderProtocol {
public static let shared = NetworkLoader()

public var session: URLSessionProtocol = URLSession.shared
public var decoder: JSONDecoder = JSONDecoder()
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@

import Foundation

protocol URLSessionProtocol {
public protocol URLSessionProtocol {
func data(for request: URLRequest, delegate: URLSessionTaskDelegate?) async throws -> (Data, URLResponse)
}

extension URLSession: URLSessionProtocol { }

protocol NetworkLoaderProtocol {
public protocol NetworkLoaderProtocol {
var session: URLSessionProtocol { get set }
var decoder: JSONDecoder { get set }

func request<T: Decodable>(with requestObject: RequestObject, responseModel: T.Type) async throws -> T
}

extension NetworkLoaderProtocol {
func request<T: Decodable>(with requestObject: RequestObject, responseModel: T.Type) async throws -> T {
public func request<T: Decodable>(with requestObject: RequestObject, responseModel: T.Type) async throws -> T {
let (data, response) = try await session.data(for: prepareURLRequest(with: requestObject), delegate: nil)
let successCodeRange = 200...299
guard let statusCode = (response as? HTTPURLResponse)?.statusCode else { throw AdessoError.badResponse }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Configuration.swift
// NetworkService
//
// Created by Abay, Batuhan on 6.12.2023.
//

import Foundation

final class Configuration: ConfigurationProtocol {
static var baseURL: String {
let url: String? = try? self.value(for: "base_url")
return url ?? ""
}

static var coinApiKey: String {
let key: String? = try? self.value(for: "personal_api")
guard let key, !key.isEmpty else {
/// Get your API key from https://www.cryptocompare.com/
#warning("Please Enter an API Key")
return ""
}
return key
}

static var webSocketBaseUrl: String {
let url: String? = try? self.value(for: "webSocket_base_url")
return url ?? ""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// ConfigurationError.swift
// NetworkService
//
// Created by Abay, Batuhan on 6.12.2023.
//

import Foundation

enum ConfigurationError: Swift.Error {
case missingKey, invalidValue
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// ConfigurationProtocol.swift
// NetworkService
//
// Created by Abay, Batuhan on 6.12.2023.
//

import Foundation

protocol ConfigurationProtocol {}

extension ConfigurationProtocol {
static func value<T>(for key: String) throws -> T where T: LosslessStringConvertible {
guard let object = Bundle.main.object(forInfoDictionaryKey: key) else {
throw ConfigurationError.missingKey
}

switch object {
case let value as T:
return value
case let string as String:
guard let value = T(string) else { fallthrough }
return value
default:
throw ConfigurationError.invalidValue
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// AllCoinEndpoints.swift
// NetworkService
//
// Created by Abay, Batuhan on 6.12.2023.
//

import Foundation

enum AllCoinEndpoints: TargetEndpointProtocol {
case allCoin(limit: Int, unitToBeConverted: String, page: Int)

private struct Constants {
static let allCoinEndpoint = "top/mktcapfull?limit=%d&tsym=%@&page=%d&api_key=%@"
}

var path: String {
switch self {
case .allCoin(let limit, let toConvert, let page):
return BaseEndpoints.base.path + String(format: Constants.allCoinEndpoint, limit, toConvert, page, Configuration.coinApiKey)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// BaseEndpoint.swift
// BaseEndpoints.swift
// SampleAppSwiftUI
//
// Created by Saglam, Fatih on 11.01.2023.
Expand All @@ -8,7 +8,11 @@

import Foundation

enum BaseEndpoint: TargetEndpointProtocol {
protocol TargetEndpointProtocol {
var path: String { get }
}

enum BaseEndpoints: TargetEndpointProtocol {
case base

var path: String {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//
// CoinNewsServiceEndpoint.swift
// SampleAppSwiftUI
// CoinNewsEndpoints.swift
// NetworkService
//
// Created by Meryem Şahin on 20.07.2023.
// Created by Abay, Batuhan on 6.12.2023.
//

import Foundation

enum CoinNewsServiceEndpoint: TargetEndpointProtocol {
enum CoinNewsEndpoints: TargetEndpointProtocol {

case coinNews(coinCode: String)

Expand All @@ -18,7 +18,7 @@ enum CoinNewsServiceEndpoint: TargetEndpointProtocol {
var path: String {
switch self {
case .coinNews(coinCode: let coinCode):
return BaseEndpoint.base.path + String(format: Constants.coinNewsEndpoint, coinCode, Configuration.coinApiKey)
return BaseEndpoints.base.path + String(format: Constants.coinNewsEndpoint, coinCode, Configuration.coinApiKey)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// CoinPriceHistoryEndpoints.swift
// NetworkService
//
// Created by Abay, Batuhan on 6.12.2023.
//

import Foundation

enum CoinPriceHistoryEndpoints: TargetEndpointProtocol {
case daily(coinCode: String, unitToBeConverted: String, dayLimit: Int, aggregate: Int)
case hourly(coinCode: String, unitToBeConverted: String, hourLimit: Int, aggregate: Int)

private struct Constants {
static let dailyEndpoint = "v2/histoday?fsym=%@&tsym=%@&limit=%d&aggregate=%d&api_key=%@"
static let hourlyEndpoint = "v2/histohour?fsym=%@&tsym=%@&limit=%d&aggregate=%d&api_key=%@"
}

var path: String {
switch self {
case .daily(let coinCode, let unitToBeConverted, let dayLimit, let aggregate):
return BaseEndpoints.base.path + String(format: Constants.dailyEndpoint, coinCode, unitToBeConverted, dayLimit, aggregate, Configuration.coinApiKey)
case .hourly(let coinCode, let unitToBeConverted, let hourLimit, let aggregate):
return BaseEndpoints.base.path + String(format: Constants.hourlyEndpoint, coinCode, unitToBeConverted, hourLimit, aggregate, Configuration.coinApiKey)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// ExampleServiceEndpoint.swift
// ExampleEndpoints.swift
// SampleAppSwiftUI
//
// Created by Saglam, Fatih on 16.01.2023.
Expand All @@ -8,7 +8,7 @@

import Foundation

enum ExampleServiceEndpoint: TargetEndpointProtocol {
enum ExampleEndpoints: TargetEndpointProtocol {
case example(firstParameter: String, secondParameter: String)

private struct Constants {
Expand All @@ -18,7 +18,7 @@ enum ExampleServiceEndpoint: TargetEndpointProtocol {
var path: String {
switch self {
case .example(let firstParameter, let secondParameter):
return BaseEndpoint.base.path + String(format: Constants.exampleEndpoint, firstParameter, secondParameter)
return BaseEndpoints.base.path + String(format: Constants.exampleEndpoint, firstParameter, secondParameter)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import Foundation

enum AdessoError: Error, Equatable {
public enum AdessoError: Error, Equatable {
case httpError(status: HTTPStatus, data: Data? = nil)
case badURL(_ url: String)
case unknown(error: NSError)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

import Foundation

class ErrorResponse: Decodable {
var code: Int?
var message: String?
var messages: [String: String]?
public class ErrorResponse: Decodable {
public var code: Int?
public var message: String?
public var messages: [String: String]?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Foundation

public enum HTTPMethod: String {
case delete = "DELETE"
case get = "GET"
case patch = "PATCH"
case post = "POST"
case put = "PUT"
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import Foundation

enum HTTPStatus: Int, Error {
public enum HTTPStatus: Int, Error {
// Default
case notValidCode = 0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

import Foundation

struct RequestObject {
public struct RequestObject {
var url: String
let method: HTTPMethod
var data: Encodable?
var headers: [String: String]?

init(url: String,
public init(url: String,
method: HTTPMethod = .get,
data: Encodable? = nil,
headers: [String: String] = [:]) {
Expand All @@ -24,11 +24,3 @@ struct RequestObject {
self.headers = headers
}
}

enum HTTPMethod: String {
case delete = "DELETE"
case get = "GET"
case patch = "PATCH"
case post = "POST"
case put = "PUT"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// CodableExtensions.swift
// SampleAppSwiftUI
//
// Created by Alver, Tunay on 5.04.2023.
//

import Foundation

public extension Encodable {
func encode() -> Data? {
let encoder = JSONEncoder()
encoder.dataEncodingStrategy = .deferredToData
return try? encoder.encode(self)
}

func encode() -> String? {
let encoder = JSONEncoder()
encoder.dataEncodingStrategy = .deferredToData
if let jsonData = try? encoder.encode(self) {
return String(data: jsonData, encoding: .utf8)
}
return nil
}
}

public extension Decodable {
static func decode(_ data: Data) -> Self? {
let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .deferredToData
return try? decoder.decode(self, from: data)
}

static func decode(_ data: String) -> Self? {
let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .deferredToData
return try? decoder.decode(self, from: Data(data.utf8))
}
}
Loading

0 comments on commit cbc596f

Please sign in to comment.