-
-
Notifications
You must be signed in to change notification settings - Fork 69
/
Copy pathAPI.swift
258 lines (238 loc) · 8.97 KB
/
API.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
//
// API.swift
// ParseSwift
//
// Created by Florent Vilmart on 17-08-19.
// Copyright © 2017 Parse. All rights reserved.
//
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
// swiftlint:disable line_length
/// The REST API for communicating with a Parse Server.
public struct API {
internal enum Method: String, Encodable {
case GET, POST, PUT, PATCH, DELETE
}
internal enum Endpoint: Encodable {
case batch
case objects(className: String)
case object(className: String, objectId: String)
case users
case user(objectId: String)
case installations
case installation(objectId: String)
case sessions
case session(objectId: String)
case event(event: String)
case roles
case role(objectId: String)
case login
case logout
case file(fileName: String)
case passwordReset
case verifyPassword
case verificationEmail
case functions(name: String)
case jobs(name: String)
case aggregate(className: String)
case config
case health
case schemas
case schema(className: String)
case purge(className: String)
case push
case hookFunctions
case hookFunction(request: FunctionRequest)
case hookTriggers
case hookTrigger(request: TriggerRequest)
case any(String)
var urlComponent: String {
switch self {
case .batch:
return "/batch"
case .objects(let className):
return "/classes/\(className)"
case .object(let className, let objectId):
return "/classes/\(className)/\(objectId)"
case .users:
return "/users"
case .user(let objectId):
return "/users/\(objectId)"
case .installations:
return "/installations"
case .installation(let objectId):
return "/installations/\(objectId)"
case .sessions:
return "/sessions"
case .session(let objectId):
return "/sessions/\(objectId)"
case .event(let event):
return "/events/\(event)"
case .aggregate(let className):
return "/aggregate/\(className)"
case .roles:
return "/roles"
case .role(let objectId):
return "/roles/\(objectId)"
case .login:
return "/login"
case .logout:
return "/logout"
case .file(let fileName):
return "/files/\(fileName)"
case .passwordReset:
return "/requestPasswordReset"
case .verifyPassword:
return "/verifyPassword"
case .verificationEmail:
return "/verificationEmailRequest"
case .functions(name: let name):
return "/functions/\(name)"
case .jobs(name: let name):
return "/jobs/\(name)"
case .config:
return "/config"
case .health:
return "/health"
case .schemas:
return "/schemas"
case .schema(let className):
return "/schemas/\(className)"
case .purge(let className):
return "/purge/\(className)"
case .push:
return "/push"
case .hookFunctions:
return "/hooks/functions/"
case .hookFunction(let request):
return "/hooks/functions/\(request.functionName)"
case .hookTriggers:
return "/hooks/triggers/"
case .hookTrigger(let request):
return "/hooks/triggers/\(request.className)/\(request.triggerName)"
case .any(let path):
return path
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(urlComponent)
}
}
/// A type alias for the set of options.
public typealias Options = Set<API.Option>
/// Options available to send to Parse Server.
public enum Option: Hashable {
/// Use the masterKey if it was provided during initial configuraration.
case useMasterKey // swiftlint:disable:this inclusive_language
/// Use a specific session token.
/// - note: The session token of the current user is provided by default.
case sessionToken(String)
/// Use a specific installationId.
/// - note: The installationId of the current user is provided by default.
case installationId(String)
/// Specify mimeType.
case mimeType(String)
/// Specify fileSize.
case fileSize(String)
/// Remove mimeType.
/// - note: This is typically used indirectly by `ParseFile`.
case removeMimeType
/// Specify metadata.
/// - note: This is typically used indirectly by `ParseFile`.
case metadata([String: String])
/// Specify tags.
/// - note: This is typically used indirectly by `ParseFile`.
case tags([String: String])
/// Add context.
/// - warning: Requires Parse Server 5.0.0+.
case context(Encodable)
/// The caching policy to use for a specific http request. Determines when to
/// return a response from the cache. See Apple's
/// [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data)
/// for more info.
case cachePolicy(URLRequest.CachePolicy)
public func hash(into hasher: inout Hasher) {
switch self {
case .useMasterKey:
hasher.combine(1)
case .sessionToken:
hasher.combine(2)
case .installationId:
hasher.combine(3)
case .mimeType:
hasher.combine(4)
case .fileSize:
hasher.combine(5)
case .removeMimeType:
hasher.combine(6)
case .metadata:
hasher.combine(7)
case .tags:
hasher.combine(8)
case .context:
hasher.combine(9)
case .cachePolicy:
hasher.combine(10)
}
}
public static func == (lhs: API.Option, rhs: API.Option) -> Bool {
lhs.hashValue == rhs.hashValue
}
}
// swiftlint:disable:next cyclomatic_complexity
internal static func getHeaders(options: API.Options) -> [String: String] {
var headers: [String: String] = ["X-Parse-Application-Id": Parse.configuration.applicationId,
"Content-Type": "application/json"]
if let clientKey = Parse.configuration.clientKey {
headers["X-Parse-Client-Key"] = clientKey
}
if let token = BaseParseUser.currentContainer?.sessionToken {
headers["X-Parse-Session-Token"] = token
}
if let installationId = BaseParseInstallation.currentContainer.installationId {
headers["X-Parse-Installation-Id"] = installationId
}
headers["X-Parse-Client-Version"] = clientVersion()
headers["X-Parse-Request-Id"] = UUID().uuidString.lowercased()
options.forEach { (option) in
switch option {
case .useMasterKey:
headers["X-Parse-Master-Key"] = Parse.configuration.masterKey
case .sessionToken(let sessionToken):
headers["X-Parse-Session-Token"] = sessionToken
case .installationId(let installationId):
headers["X-Parse-Installation-Id"] = installationId
case .mimeType(let mimeType):
headers["Content-Type"] = mimeType
case .fileSize(let fileSize):
headers["Content-Length"] = fileSize
case .removeMimeType:
headers.removeValue(forKey: "Content-Type")
case .metadata(let metadata):
metadata.forEach {(key, value) -> Void in
headers[key] = value
}
case .tags(let tags):
tags.forEach {(key, value) -> Void in
headers[key] = value
}
case .context(let context):
let context = AnyEncodable(context)
if let encoded = try? ParseCoding.jsonEncoder().encode(context),
let encodedString = String(data: encoded, encoding: .utf8) {
headers["X-Parse-Cloud-Context"] = encodedString
}
default:
break
}
}
return headers
}
internal static func clientVersion() -> String {
ParseConstants.sdk+ParseConstants.version
}
}
// swiftlint:enable line_length