Skip to content

Commit 11b48a7

Browse files
authored
Future proof SDK by always sending clientVersion header (#146)
* Future proof SDK by always sending clientVersion header * Add patch header test
1 parent 608a69f commit 11b48a7

File tree

8 files changed

+108
-10
lines changed

8 files changed

+108
-10
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.7.2...main)
55
* _Contributing to this repo? Add info about your change here to be included in the next release_
66

7+
__Improvements__
8+
- Future proof SDK by always sending client version header. Also added http method PATCH to API for future use ([#146](https://github.com/parse-community/Parse-Swift/pull/146)), thanks to [Corey Baker](https://github.com/cbaker6).
9+
710
### 1.7.2
811
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.7.1...1.7.2)
912

ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ struct GameScore: ParseObject {
7171
let score = GameScore(score: 10)
7272

7373
//: Save asynchronously (preferred way) with the context option.
74-
score.save(options: .init(.context(["hello": "world"]))) { result in
74+
score.save(options: [.context(["hello": "world"])]) { result in
7575
switch result {
7676
case .success(let savedScore):
7777
print("Successfully saved \(savedScore)")

ParseSwift.playground/contents.xcplayground

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@
1717
<page name='14 - Config'/>
1818
<page name='15 - Custom ObjectId'/>
1919
</pages>
20-
</playground>
20+
</playground>

Sources/ParseSwift/API/API+Commands.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ internal extension API {
5858
switch self.prepareURLRequest(options: options, childObjects: childObjects, childFiles: childFiles) {
5959

6060
case .success(let urlRequest):
61-
if method == .POST || method == .PUT {
61+
if method == .POST || method == .PUT || method == .PATCH {
6262
let task = URLSession.parse.uploadTask(withStreamedRequest: urlRequest)
6363
ParseSwift.sessionDelegate.uploadDelegates[task] = uploadProgress
6464
ParseSwift.sessionDelegate.streamDelegates[task] = stream
@@ -128,7 +128,7 @@ internal extension API {
128128
}
129129
} else {
130130
//ParseFiles are handled with a dedicated URLSession
131-
if method == .POST || method == .PUT {
131+
if method == .POST || method == .PUT || method == .PATCH {
132132
switch self.prepareURLRequest(options: options,
133133
childObjects: childObjects,
134134
childFiles: childFiles) {
@@ -204,7 +204,7 @@ internal extension API {
204204
childFiles: [UUID: ParseFile]? = nil) -> Result<URLRequest, ParseError> {
205205
let params = self.params?.getQueryItems()
206206
var headers = API.getHeaders(options: options)
207-
if !(method == .POST) && !(method == .PUT) {
207+
if !(method == .POST) && !(method == .PUT) && !(method == .PATCH) {
208208
headers.removeValue(forKey: "X-Parse-Request-Id")
209209
}
210210
let url = parseURL == nil ?
@@ -622,7 +622,7 @@ internal extension API {
622622
// MARK: URL Preperation
623623
func prepareURLRequest(options: API.Options) -> Result<URLRequest, ParseError> {
624624
var headers = API.getHeaders(options: options)
625-
if !(method == .POST) && !(method == .PUT) {
625+
if !(method == .POST) && !(method == .PUT) && !(method == .PATCH) {
626626
headers.removeValue(forKey: "X-Parse-Request-Id")
627627
}
628628
let url = ParseSwift.configuration.serverURL.appendingPathComponent(path.urlComponent)

Sources/ParseSwift/API/API.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import Foundation
1212
public struct API {
1313

1414
internal enum Method: String, Encodable {
15-
case GET, POST, PUT, DELETE
15+
case GET, POST, PUT, PATCH, DELETE
1616
}
1717

1818
internal enum Endpoint: Encodable {
@@ -169,6 +169,7 @@ public struct API {
169169
headers["X-Parse-Installation-Id"] = installationId
170170
}
171171

172+
headers["X-Parse-Client-Version"] = clientVersion()
172173
headers["X-Parse-Request-Id"] = UUID().uuidString.lowercased()
173174

174175
options.forEach { (option) in
@@ -204,6 +205,10 @@ public struct API {
204205

205206
return headers
206207
}
208+
209+
internal static func clientVersion() -> String {
210+
ParseConstants.sdk+ParseConstants.version
211+
}
207212
}
208213

209214
internal extension Dictionary where Key == String, Value == String? {

Sources/ParseSwift/Objects/ParseInstallation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,8 @@ extension ParseInstallation {
272272
}
273273
#endif
274274

275-
if parseVersion != ParseConstants.parseVersion {
276-
parseVersion = ParseConstants.parseVersion
275+
if parseVersion != ParseConstants.version {
276+
parseVersion = ParseConstants.version
277277
}
278278
}
279279

Sources/ParseSwift/ParseConstants.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
import Foundation
1010

1111
enum ParseConstants {
12-
static let parseVersion = "1.7.2"
12+
static let sdk = "swift"
13+
static let version = "1.7.2"
1314
static let hashingKey = "parseSwift"
1415
static let fileManagementDirectory = "parse/"
1516
static let fileManagementPrivateDocumentsDirectory = "Private Documents/"

Tests/ParseSwiftTests/APICommandTests.swift

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,95 @@ class APICommandTests: XCTestCase {
440440
}
441441
}
442442

443+
func testClientVersionAPIMethod() {
444+
let clientVersion = API.clientVersion()
445+
XCTAssertTrue(clientVersion.contains(ParseConstants.sdk))
446+
XCTAssertTrue(clientVersion.contains(ParseConstants.version))
447+
448+
let splitString = clientVersion
449+
.components(separatedBy: ParseConstants.sdk)
450+
XCTAssertEqual(splitString.count, 2)
451+
//If successful, will remove `swift` resulting in ""
452+
XCTAssertEqual(splitString[0], "")
453+
XCTAssertEqual(splitString[1], ParseConstants.version)
454+
455+
//Test incorrect split
456+
let splitString2 = clientVersion
457+
.components(separatedBy: "hello")
458+
XCTAssertEqual(splitString2.count, 1)
459+
XCTAssertEqual(splitString2[0], clientVersion)
460+
}
461+
462+
func testClientVersionHeader() {
463+
let headers = API.getHeaders(options: [])
464+
XCTAssertEqual(headers["X-Parse-Client-Version"], API.clientVersion())
465+
466+
let post = API.Command<Level, NoBody?>(method: .POST, path: .login) { _ in
467+
return nil
468+
}
469+
switch post.prepareURLRequest(options: []) {
470+
471+
case .success(let request):
472+
if request.allHTTPHeaderFields?["X-Parse-Client-Version"] != API.clientVersion() {
473+
XCTFail("Should contain correct Client Version header")
474+
}
475+
case .failure(let error):
476+
XCTFail(error.localizedDescription)
477+
}
478+
479+
let put = API.Command<Level, NoBody?>(method: .PUT, path: .login) { _ in
480+
return nil
481+
}
482+
switch put.prepareURLRequest(options: []) {
483+
484+
case .success(let request):
485+
if request.allHTTPHeaderFields?["X-Parse-Client-Version"] != API.clientVersion() {
486+
XCTFail("Should contain correct Client Version header")
487+
}
488+
case .failure(let error):
489+
XCTFail(error.localizedDescription)
490+
}
491+
492+
let patch = API.Command<Level, NoBody?>(method: .PATCH, path: .login) { _ in
493+
return nil
494+
}
495+
switch patch.prepareURLRequest(options: []) {
496+
497+
case .success(let request):
498+
if request.allHTTPHeaderFields?["X-Parse-Client-Version"] != API.clientVersion() {
499+
XCTFail("Should contain correct Client Version header")
500+
}
501+
case .failure(let error):
502+
XCTFail(error.localizedDescription)
503+
}
504+
505+
let delete = API.Command<Level, NoBody?>(method: .DELETE, path: .login) { _ in
506+
return nil
507+
}
508+
switch delete.prepareURLRequest(options: []) {
509+
510+
case .success(let request):
511+
if request.allHTTPHeaderFields?["X-Parse-Client-Version"] != API.clientVersion() {
512+
XCTFail("Should contain correct Client Version header")
513+
}
514+
case .failure(let error):
515+
XCTFail(error.localizedDescription)
516+
}
517+
518+
let get = API.Command<Level, NoBody?>(method: .GET, path: .login) { _ in
519+
return nil
520+
}
521+
switch get.prepareURLRequest(options: []) {
522+
523+
case .success(let request):
524+
if request.allHTTPHeaderFields?["X-Parse-Client-Version"] != API.clientVersion() {
525+
XCTFail("Should contain correct Client Version header")
526+
}
527+
case .failure(let error):
528+
XCTFail(error.localizedDescription)
529+
}
530+
}
531+
443532
func testIdempodency() {
444533
let headers = API.getHeaders(options: [])
445534
XCTAssertNotNil(headers["X-Parse-Request-Id"])

0 commit comments

Comments
 (0)