From ae014375ed3f1567b16af479a534897151269ca9 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 17 Oct 2019 01:23:00 -0400 Subject: [PATCH 1/2] QueryItem helper --- .../Account/Account.xcodeproj/project.pbxproj | 4 +++ Frameworks/Account/URL+Extensions.swift | 30 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 Frameworks/Account/URL+Extensions.swift diff --git a/Frameworks/Account/Account.xcodeproj/project.pbxproj b/Frameworks/Account/Account.xcodeproj/project.pbxproj index 0f04f4032..8f7abd3ee 100644 --- a/Frameworks/Account/Account.xcodeproj/project.pbxproj +++ b/Frameworks/Account/Account.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 3BF611F223583530000EF978 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF611E62358352F000EF978 /* URL+Extensions.swift */; }; 5107A099227DE42E00C7C3C5 /* AccountCredentialsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5107A098227DE42E00C7C3C5 /* AccountCredentialsTest.swift */; }; 5107A09B227DE49500C7C3C5 /* TestAccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5107A09A227DE49500C7C3C5 /* TestAccountManager.swift */; }; 5107A09D227DE77700C7C3C5 /* TestTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5107A09C227DE77700C7C3C5 /* TestTransport.swift */; }; @@ -185,6 +186,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 3BF611E62358352F000EF978 /* URL+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URL+Extensions.swift"; sourceTree = ""; }; 5107A098227DE42E00C7C3C5 /* AccountCredentialsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountCredentialsTest.swift; sourceTree = ""; }; 5107A09A227DE49500C7C3C5 /* TestAccountManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestAccountManager.swift; sourceTree = ""; }; 5107A09C227DE77700C7C3C5 /* TestTransport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestTransport.swift; sourceTree = ""; }; @@ -480,6 +482,7 @@ 841974001F6DD1EC006346C4 /* Folder.swift */, 844B297E210CE37E004020B3 /* UnreadCountProvider.swift */, 51FE1007234635A20056195D /* DeepLinkProvider.swift */, + 3BF611E62358352F000EF978 /* URL+Extensions.swift */, 5165D71F22835E9800D9D53D /* FeedFinder */, 515E4EB12324FF7D0057B0E7 /* Credentials */, 8419742B1F6DDE84006346C4 /* LocalAccount */, @@ -909,6 +912,7 @@ 9E1773D5234570E30056A5A8 /* FeedlyEntryParser.swift in Sources */, 9E1D1555233431A600F4944C /* FeedlyOperation.swift in Sources */, 9E1AF38B2353D41A008BD1D5 /* FeedlySetStarredArticlesOperation.swift in Sources */, + 3BF611F223583530000EF978 /* URL+Extensions.swift in Sources */, 84F1F06E2243524700DA0616 /* AccountMetadata.swift in Sources */, 84245C851FDDD8CB0074AFBB /* FeedbinSubscription.swift in Sources */, ); diff --git a/Frameworks/Account/URL+Extensions.swift b/Frameworks/Account/URL+Extensions.swift new file mode 100644 index 000000000..69a048ac8 --- /dev/null +++ b/Frameworks/Account/URL+Extensions.swift @@ -0,0 +1,30 @@ +// +// URL+Extensions.swift +// Account +// +// Created by Jonathan Bennett on 2019-10-16. +// Copyright © 2019 Ranchero Software, LLC. All rights reserved. +// + +import Foundation + + +public extension URL { + + func appendingQueryItem(_ queryItem: URLQueryItem) -> URL? { + appendingQueryItems([queryItem]) + } + + func appendingQueryItems(_ queryItems: [URLQueryItem]) -> URL? { + guard var components = URLComponents(url: self, resolvingAgainstBaseURL: false) else { + return nil + } + + var newQueryItems = components.queryItems ?? [] + newQueryItems.append(contentsOf: queryItems) + components.queryItems = newQueryItems + + return components.url + } + +} From d70c996c06146d3d910b5e1e006610257b2d4f70 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 17 Oct 2019 01:56:42 -0400 Subject: [PATCH 2/2] use the URLQueryItem helper --- .../Account/Feedbin/FeedbinAPICaller.swift | 32 +++-- .../Account/ReaderAPI/ReaderAPICaller.swift | 114 +++++++----------- 2 files changed, 64 insertions(+), 82 deletions(-) diff --git a/Frameworks/Account/Feedbin/FeedbinAPICaller.swift b/Frameworks/Account/Feedbin/FeedbinAPICaller.swift index 8f46c00bc..ff8cd03e0 100644 --- a/Frameworks/Account/Feedbin/FeedbinAPICaller.swift +++ b/Frameworks/Account/Feedbin/FeedbinAPICaller.swift @@ -339,9 +339,13 @@ final class FeedbinAPICaller: NSObject { let concatIDs = articleIDs.reduce("") { param, articleID in return param + ",\(articleID)" } let paramIDs = String(concatIDs.dropFirst()) - var callComponents = URLComponents(url: feedbinBaseURL.appendingPathComponent("entries.json"), resolvingAgainstBaseURL: false)! - callComponents.queryItems = [URLQueryItem(name: "ids", value: paramIDs), URLQueryItem(name: "mode", value: "extended")] - let request = URLRequest(url: callComponents.url!, credentials: credentials) + let url = feedbinBaseURL + .appendingPathComponent("entries.json") + .appendingQueryItems([ + URLQueryItem(name: "ids", value: paramIDs), + URLQueryItem(name: "mode", value: "extended") + ]) + let request = URLRequest(url: url!, credentials: credentials) transport.send(request: request, resultType: [FeedbinEntry].self) { result in @@ -361,9 +365,14 @@ final class FeedbinAPICaller: NSObject { let since = Calendar.current.date(byAdding: .month, value: -3, to: Date()) ?? Date() let sinceString = FeedbinDate.formatter.string(from: since) - var callComponents = URLComponents(url: feedbinBaseURL.appendingPathComponent("feeds/\(feedID)/entries.json"), resolvingAgainstBaseURL: false)! - callComponents.queryItems = [URLQueryItem(name: "since", value: sinceString), URLQueryItem(name: "per_page", value: "100"), URLQueryItem(name: "mode", value: "extended")] - let request = URLRequest(url: callComponents.url!, credentials: credentials) + let url = feedbinBaseURL + .appendingPathComponent("feeds/\(feedID)/entries.json") + .appendingQueryItems([ + URLQueryItem(name: "since", value: sinceString), + URLQueryItem(name: "per_page", value: "100"), + URLQueryItem(name: "mode", value: "extended") + ]) + let request = URLRequest(url: url!, credentials: credentials) transport.send(request: request, resultType: [FeedbinEntry].self) { result in @@ -392,9 +401,14 @@ final class FeedbinAPICaller: NSObject { }() let sinceString = FeedbinDate.formatter.string(from: since) - var callComponents = URLComponents(url: feedbinBaseURL.appendingPathComponent("entries.json"), resolvingAgainstBaseURL: false)! - callComponents.queryItems = [URLQueryItem(name: "since", value: sinceString), URLQueryItem(name: "per_page", value: "100"), URLQueryItem(name: "mode", value: "extended")] - let request = URLRequest(url: callComponents.url!, credentials: credentials) + let url = feedbinBaseURL + .appendingPathComponent("entries.json") + .appendingQueryItems([ + URLQueryItem(name: "since", value: sinceString), + URLQueryItem(name: "per_page", value: "100"), + URLQueryItem(name: "mode", value: "extended") + ]) + let request = URLRequest(url: url!, credentials: credentials) transport.send(request: request, resultType: [FeedbinEntry].self) { result in diff --git a/Frameworks/Account/ReaderAPI/ReaderAPICaller.swift b/Frameworks/Account/ReaderAPI/ReaderAPICaller.swift index 23499a9c0..ba1234a81 100644 --- a/Frameworks/Account/ReaderAPI/ReaderAPICaller.swift +++ b/Frameworks/Account/ReaderAPI/ReaderAPICaller.swift @@ -166,17 +166,11 @@ final class ReaderAPICaller: NSObject { return } - // Add query string for getting JSON (probably should break this out as I will be doing it a lot) - guard var components = URLComponents(url: baseURL.appendingPathComponent(ReaderAPIEndpoints.tagList.rawValue), resolvingAgainstBaseURL: false) else { - completion(.failure(TransportError.noURL)) - return - } + let url = baseURL + .appendingPathComponent(ReaderAPIEndpoints.tagList.rawValue) + .appendingQueryItem(URLQueryItem(name: "output", value: "json")) - components.queryItems = [ - URLQueryItem(name: "output", value: "json") - ] - - guard let callURL = components.url else { + guard let callURL = url else { completion(.failure(TransportError.noURL)) return } @@ -278,17 +272,11 @@ final class ReaderAPICaller: NSObject { return } - // Add query string for getting JSON (probably should break this out as I will be doing it a lot) - guard var components = URLComponents(url: baseURL.appendingPathComponent(ReaderAPIEndpoints.subscriptionList.rawValue), resolvingAgainstBaseURL: false) else { - completion(.failure(TransportError.noURL)) - return - } + let url = baseURL + .appendingPathComponent(ReaderAPIEndpoints.subscriptionList.rawValue) + .appendingQueryItem(URLQueryItem(name: "output", value: "json")) - components.queryItems = [ - URLQueryItem(name: "output", value: "json") - ] - - guard let callURL = components.url else { + guard let callURL = url else { completion(.failure(TransportError.noURL)) return } @@ -333,16 +321,11 @@ final class ReaderAPICaller: NSObject { self.requestAuthorizationToken(endpoint: baseURL) { (result) in switch result { case .success(let token): - guard var components = URLComponents(url: baseURL.appendingPathComponent(ReaderAPIEndpoints.subscriptionAdd.rawValue), resolvingAgainstBaseURL: false) else { - completion(.failure(TransportError.noURL)) - return - } + let url = baseURL + .appendingPathComponent(ReaderAPIEndpoints.subscriptionAdd.rawValue) + .appendingQueryItem(URLQueryItem(name: "quickadd", value: url.absoluteString)) - components.queryItems = [ - URLQueryItem(name: "quickadd", value: url.absoluteString) - ] - - guard let callURL = components.url else { + guard let callURL = url else { completion(.failure(TransportError.noURL)) return } @@ -616,19 +599,15 @@ final class ReaderAPICaller: NSObject { return } - // Add query string for getting JSON (probably should break this out as I will be doing it a lot) - guard var components = URLComponents(url: baseURL.appendingPathComponent(ReaderAPIEndpoints.itemIds.rawValue), resolvingAgainstBaseURL: false) else { - completion(.failure(TransportError.noURL)) - return - } + let url = baseURL + .appendingPathComponent(ReaderAPIEndpoints.itemIds.rawValue) + .appendingQueryItems([ + URLQueryItem(name: "s", value: feedID), + URLQueryItem(name: "ot", value: String(since.timeIntervalSince1970)), + URLQueryItem(name: "output", value: "json") + ]) - components.queryItems = [ - URLQueryItem(name: "s", value: feedID), - URLQueryItem(name: "ot", value: String(since.timeIntervalSince1970)), - URLQueryItem(name: "output", value: "json") - ] - - guard let callURL = components.url else { + guard let callURL = url else { completion(.failure(TransportError.noURL)) return } @@ -684,22 +663,17 @@ final class ReaderAPICaller: NSObject { }() let sinceString = since.timeIntervalSince1970 + let url = baseURL + .appendingPathComponent(ReaderAPIEndpoints.itemIds.rawValue) + .appendingQueryItems([ + URLQueryItem(name: "o", value: String(sinceString)), + URLQueryItem(name: "n", value: "10000"), + URLQueryItem(name: "output", value: "json"), + URLQueryItem(name: "xt", value: ReaderState.read.rawValue), + URLQueryItem(name: "s", value: ReaderStreams.readingList.rawValue) + ]) - // Add query string for getting JSON (probably should break this out as I will be doing it a lot) - guard var components = URLComponents(url: baseURL.appendingPathComponent(ReaderAPIEndpoints.itemIds.rawValue), resolvingAgainstBaseURL: false) else { - completion(.failure(TransportError.noURL)) - return - } - - components.queryItems = [ - URLQueryItem(name: "o", value: String(sinceString)), - URLQueryItem(name: "n", value: "10000"), - URLQueryItem(name: "output", value: "json"), - URLQueryItem(name: "xt", value: ReaderState.read.rawValue), - URLQueryItem(name: "s", value: ReaderStreams.readingList.rawValue) - ] - - guard let callURL = components.url else { + guard let callURL = url else { completion(.failure(TransportError.noURL)) return } @@ -768,13 +742,11 @@ final class ReaderAPICaller: NSObject { func retrieveEntries(page: String, completion: @escaping (Result<([ReaderAPIEntry]?, String?), Error>) -> Void) { - guard let url = URL(string: page), var callComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else { + guard let url = URL(string: page)?.appendingQueryItem(URLQueryItem(name: "mode", value: "extended")) else { completion(.success((nil, nil))) return } - - callComponents.queryItems?.append(URLQueryItem(name: "mode", value: "extended")) - let request = URLRequest(url: callComponents.url!, credentials: credentials) + let request = URLRequest(url: url, credentials: credentials) transport.send(request: request, resultType: [ReaderAPIEntry].self) { result in @@ -800,20 +772,16 @@ final class ReaderAPICaller: NSObject { return } - // Add query string for getting JSON (probably should break this out as I will be doing it a lot) - guard var components = URLComponents(url: baseURL.appendingPathComponent(ReaderAPIEndpoints.itemIds.rawValue), resolvingAgainstBaseURL: false) else { - completion(.failure(TransportError.noURL)) - return - } + let url = baseURL + .appendingPathComponent(ReaderAPIEndpoints.itemIds.rawValue) + .appendingQueryItems([ + URLQueryItem(name: "s", value: ReaderStreams.readingList.rawValue), + URLQueryItem(name: "n", value: "10000"), + URLQueryItem(name: "xt", value: ReaderState.read.rawValue), + URLQueryItem(name: "output", value: "json") + ]) - components.queryItems = [ - URLQueryItem(name: "s", value: ReaderStreams.readingList.rawValue), - URLQueryItem(name: "n", value: "10000"), - URLQueryItem(name: "xt", value: ReaderState.read.rawValue), - URLQueryItem(name: "output", value: "json") - ] - - guard let callURL = components.url else { + guard let callURL = url else { completion(.failure(TransportError.noURL)) return }