-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathAuthNetworkService.swift
103 lines (83 loc) · 3.34 KB
/
AuthNetworkService.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
95
96
97
98
99
100
101
//
// AuthNetworkService.swift
// Example
//
// Created by Amy Oulton on 2022-11-28.
// Copyright © 2022 Steamclock Software. All rights reserved.
//
import Combine
import Foundation
import Netable
class AuthNetworkService {
static let shared = AuthNetworkService()
private let unauthNetable: Netable
private var authNetable: Netable?
var netable: Netable {
authNetable ?? unauthNetable
}
var user: CurrentValueSubject<User?, Never>
var authError: CurrentValueSubject<NetableError?, Never>
var cancellables = [AnyCancellable]()
init() {
user = CurrentValueSubject<User?, Never>(nil)
authError = CurrentValueSubject<NetableError?, Never>(nil)
unauthNetable = Netable(
baseURL: URL(string: "http://localhost:8080/")!)
unauthNetable.requestFailurePublisher.sink { [weak self] error in
if error.errorCode == 401 {
self?.user.send(nil)
self?.authError.send(error)
}
}.store(in: &cancellables)
}
func login(email: String, password: String) async throws {
let login = try await netable.request(LoginRequest(parameters: LoginParameters(email: email, password: password)))
authNetable = Netable(baseURL: URL(string: "http://localhost:8080/")!,
config: Config(globalHeaders: ["Authentication" : "Bearer \(login.token)"]),
logDestination: CustomLogDestination(),
retryConfiguration: RetryConfiguration(errors: .all, count: 2, delay: 3.0),
requestFailureDelegate: ErrorService.shared)
}
func getUser() {
let (_, result) = netable.request(GetUserRequest(headers: ["Accept-Language": "en-US"]))
result.sink { result in
switch result {
case .success(let user):
self.user.send(user)
case .failure(let error):
print(error)
}
}.store(in: &cancellables)
}
func getPosts() async throws -> [Post] {
try await netable.request(GetPostsRequest())
}
@MainActor func createPost(title: String, content: String) {
// this request is deliberately failing. Since there is a retry configuration set to the authNetable request,
// we are going to make use of `cancel()` to cancel the task after sending it so it doesn't try again.
let createRequest = Task {
do {
try await netable.request(CreatePostRequest(parameters: CreatePostParameters(title: title, content: content)))
} catch {
print("Create request error: \(error)")
}
}
// to see the retry configuration in action, comment out the below line and re-run the application.
// The request will not print the error until the retry conditions have been met.
createRequest.cancel()
}
func logout() {
authNetable = nil
self.user.send(nil)
}
}
final class MockRequestInterceptor: Interceptor {
func adapt(_ request: URLRequest, instance: Netable) async throws -> AdaptedRequest {
if let requestURL = request.url,
let mockedURL = Bundle.main.url(forResource: "posts", withExtension: "json"),
requestURL.absoluteString.contains("/all") {
return .mocked(mockedURL)
}
return .notChanged
}
}