-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #576 from wordpress-mobile/feature/jetpack-proxy-r…
…emote Add Jetpack Proxy remote service
- Loading branch information
Showing
4 changed files
with
195 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/// Encapsulates Jetpack Proxy requests. | ||
public class JetpackProxyServiceRemote: ServiceRemoteWordPressComREST { | ||
|
||
/// Represents the most common HTTP methods for the proxied request. | ||
public enum DotComMethod: String { | ||
case get | ||
case post | ||
case put | ||
case delete | ||
} | ||
|
||
/// Sends a proxied request to a Jetpack-connected site through the Jetpack Proxy API. | ||
/// The proxy API expects the client to be authenticated with a WordPress.com account. | ||
/// | ||
/// - Parameters: | ||
/// - siteID: The dotcom ID of the Jetpack-connected site. | ||
/// - path: The request endpoint to be proxied. | ||
/// - method: The HTTP method for the proxied request. | ||
/// - parameters: The request parameter for the proxied request. Defaults to empty. | ||
/// - locale: The user locale, if any. Defaults to nil. | ||
/// - completion: Closure called after the request completes. | ||
/// - Returns: A Progress object, which can be used to cancel the request if needed. | ||
@discardableResult | ||
public func proxyRequest(for siteID: Int, | ||
path: String, | ||
method: DotComMethod, | ||
parameters: [String: AnyHashable] = [:], | ||
locale: String? = nil, | ||
completion: @escaping (Result<AnyObject, Error>) -> Void) -> Progress? { | ||
let urlString = self.path(forEndpoint: "jetpack-blogs/\(siteID)/rest-api", withVersion: ._1_1) | ||
|
||
// Construct the request parameters to be forwarded to the actual endpoint. | ||
var requestParams: [String: AnyHashable] = [ | ||
"json": "true", | ||
"path": "\(path)&_method=\(method.rawValue)" | ||
] | ||
|
||
// The parameters need to be encoded into a JSON string. | ||
if !parameters.isEmpty, | ||
let data = try? JSONSerialization.data(withJSONObject: parameters, options: []), | ||
let jsonString = String(data: data, encoding: .utf8) { | ||
// Use "query" for the body parameters if the method is GET. Otherwise, always use "body". | ||
let bodyParameterKey = (method == .get ? "query" : "body") | ||
requestParams[bodyParameterKey] = jsonString | ||
} | ||
|
||
if let locale, | ||
!locale.isEmpty { | ||
requestParams["locale"] = locale | ||
} | ||
|
||
return wordPressComRestApi.POST(urlString, parameters: requestParams as [String: AnyObject]) { response, _ in | ||
completion(.success(response)) | ||
} failure: { error, _ in | ||
completion(.failure(error)) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import XCTest | ||
@testable import WordPressKit | ||
|
||
class JetpackProxyServiceRemoteTests: XCTestCase { | ||
let timeout: TimeInterval = 1.0 | ||
let api = MockWordPressComRestApi() | ||
let siteID = 1001 | ||
|
||
private var remote: JetpackProxyServiceRemote { | ||
return .init(wordPressComRestApi: api) | ||
} | ||
|
||
// MARK: - Tests | ||
|
||
func testProxyRequestEndpoint() { | ||
// the mock rest API doesn't append the base URL, so we're just going to verify the path. | ||
let urlString = "rest/v1.1/jetpack-blogs/\(siteID)/rest-api" | ||
|
||
remote.proxyRequest(for: siteID, path: "path", method: .get) { _ in } | ||
|
||
guard let passedURLString = api.URLStringPassedIn else { | ||
return XCTFail() | ||
} | ||
XCTAssertTrue(passedURLString.hasSuffix(urlString)) | ||
} | ||
|
||
func testJSONParameter() { | ||
remote.proxyRequest(for: siteID, path: "path", method: .get) { _ in } | ||
|
||
guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else { | ||
return XCTFail() | ||
} | ||
XCTAssertEqual(passedParameter["json"] as? String, "true") | ||
} | ||
|
||
func testPathParameter() { | ||
let path = "/wp/v2/posts" | ||
let method = JetpackProxyServiceRemote.DotComMethod.get | ||
|
||
remote.proxyRequest(for: siteID, path: path, method: method) { _ in } | ||
|
||
guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else { | ||
return XCTFail() | ||
} | ||
XCTAssertEqual(passedParameter["path"] as? String, "\(path)&_method=\(method.rawValue)") | ||
} | ||
|
||
func testBodyParameterKeyForGETMethod() { | ||
let method = JetpackProxyServiceRemote.DotComMethod.get | ||
let params = ["key": "value"] | ||
|
||
remote.proxyRequest(for: siteID, path: "path", method: method, parameters: params) { _ in } | ||
|
||
guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else { | ||
return XCTFail() | ||
} | ||
XCTAssertNotNil(passedParameter["query"]) | ||
} | ||
|
||
func testBodyParameterKeyForPOSTMethod() { | ||
let method = JetpackProxyServiceRemote.DotComMethod.post | ||
let params = ["key": "value"] | ||
|
||
remote.proxyRequest(for: siteID, path: "path", method: method, parameters: params) { _ in } | ||
|
||
guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else { | ||
return XCTFail() | ||
} | ||
XCTAssertNotNil(passedParameter["body"]) | ||
} | ||
|
||
func testBodyParameterEncoding() { | ||
let method = JetpackProxyServiceRemote.DotComMethod.post | ||
let params = [ | ||
"key1": "value1", | ||
"key2": "value2" | ||
] | ||
|
||
remote.proxyRequest(for: siteID, path: "path", method: method, parameters: params) { _ in } | ||
|
||
guard let passedParameter = api.parametersPassedIn as? [String: AnyObject], | ||
let jsonString = passedParameter["body"] as? String, | ||
let jsonData = jsonString.data(using: .utf8), | ||
let jsonDictionary = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: String] else { | ||
return XCTFail() | ||
} | ||
XCTAssertEqual(jsonDictionary, params) | ||
} | ||
|
||
func testBodyParameterShouldNotExistWhenEmpty() { | ||
let params = [String: String]() | ||
|
||
remote.proxyRequest(for: siteID, path: "path", method: .post, parameters: params) { _ in } | ||
|
||
guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else { | ||
return XCTFail() | ||
} | ||
XCTAssertNil(passedParameter["body"]) | ||
} | ||
|
||
func testLocaleParameter() { | ||
let locale = "en_US" | ||
|
||
remote.proxyRequest(for: siteID, path: "path", method: .post, locale: locale) { _ in } | ||
|
||
guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else { | ||
return XCTFail() | ||
} | ||
XCTAssertEqual(passedParameter["locale"] as? String, locale) | ||
} | ||
|
||
func testLocaleParameterShouldNotExistWhenEmpty() { | ||
let locale = String() | ||
|
||
remote.proxyRequest(for: siteID, path: "path", method: .post, locale: locale) { _ in } | ||
|
||
guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else { | ||
return XCTFail() | ||
} | ||
XCTAssertNil(passedParameter["locale"]) | ||
} | ||
} |