-
Notifications
You must be signed in to change notification settings - Fork 0
/
NetworkService.swift
94 lines (84 loc) · 4.13 KB
/
NetworkService.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//
// NetworkService.swift
// Networking
//
// Created by Viktor Gidlöf.
//
import Foundation
import Combine
public let name = "Networking"
public let version = "0.8.9"
public enum Network {
/// A network service object used to make requests to the backend.
public final class Service {
// MARK: Private properties
private let server: ServerConfig
private let decoder: JSONDecoder
private let session: URLSession
// MARK: - Init
/// Initialize the network service
/// - parameters:
/// - server: The given server configuration
/// - session: The given URLSession object. Defaults to the shared instance.
/// - decoder: A default json decoder object
public init(server: ServerConfig, session: URLSession = .shared, decoder: JSONDecoder = JSONDecoder()) {
self.session = session
self.decoder = decoder
self.server = server
}
// MARK: - Private functions
private func dataTaskPublisher(_ request: Requestable, logResponse: Bool) throws -> AnyPublisher<URLSession.DataTaskPublisher.Output, Error> {
let config = Request.Config(request: request, server: server)
let urlRequest = try URLRequest(withConfig: config)
urlRequest.log()
return session.dataTaskPublisher(for: urlRequest)
.logResponse(printJSON: logResponse)
.receive(on: RunLoop.main)
.tryMap { $0 }
.eraseToAnyPublisher()
}
}
}
// MARK: -
public extension Network.Service {
/// Create a new publisher that contains a decoded data model object
/// - parameters:
/// - request: The request to send over the network
/// - logResponse: A boolean value that determines if the json response should be printed to the console. Defaults to false.
/// - throws: An error if the data task publisher fails for any reason
/// - returns: A new publisher with the given data model object or an error
func request<DataModel: Decodable>(_ request: Requestable, logResponse: Bool = false) throws -> AnyPublisher<DataModel, Error> {
try dataPublisher(request, logResponse: logResponse)
.decode(type: DataModel.self, decoder: decoder)
.eraseToAnyPublisher()
}
/// Create a new publisher that contains the response data
/// - parameters:
/// - request: The request to send over the network
/// - logResponse: A boolean value that determines if the json response should be printed to the console. Defaults to false.
/// - throws: An error if the data task publisher fails for any reason
/// - returns: A new publisher with the data or an error
func dataPublisher(_ request: Requestable, logResponse: Bool = false) throws -> AnyPublisher<Data, Error> {
try dataTaskPublisher(request, logResponse: logResponse)
.map(\.data)
.eraseToAnyPublisher()
}
/// Create a new publisher that contains the HTTP status code
/// - parameters:
/// - request: The request to send over the network
/// - logResponse: A boolean value that determines if the json response should be printed to the console. Defaults to false.
/// - throws: An error if the data task publisher fails for any reason
/// - returns: A new publisher with a bool value that determines if the request succeeded
func responsePublisher(_ request: Requestable, logResponse: Bool = false) throws -> AnyPublisher<HTTP.StatusCode, Error> {
try dataTaskPublisher(request, logResponse: logResponse)
.compactMap { $0.response as? HTTPURLResponse }
.map { HTTP.StatusCode(rawValue: $0.statusCode) ?? .unknown }
.eraseToAnyPublisher()
}
/// Create a new publisher that publishes file download progress and the destination of the temporary file
/// - parameter url: The URL to the file to download
/// - returns: A new download publisher with the file download progress and destination URL
func downloadPublisher(url: URL) -> Network.Service.Downloader {
Network.Service.Downloader(url: url)
}
}