Skip to content

Commit

Permalink
Add QueryParameters protocol to provide interface for URL query.
Browse files Browse the repository at this point in the history
  • Loading branch information
matsuda committed Jan 15, 2017
1 parent 5048237 commit 263ba3f
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 6 deletions.
29 changes: 29 additions & 0 deletions APIKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
0ED17E891E229EC700EC1114 /* QueryParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED17E881E229EC700EC1114 /* QueryParameters.swift */; };
0ED17E8B1E22A22900EC1114 /* URLEncodedQueryParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED17E8A1E22A22900EC1114 /* URLEncodedQueryParameters.swift */; };
0ED17E8E1E22AC8300EC1114 /* URLEncodedQueryParametersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED17E8D1E22AC8300EC1114 /* URLEncodedQueryParametersTests.swift */; };
141F12201C1C9ABE0026D415 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD5115241B1FFBA900514240 /* Result.framework */; };
141F12311C1C9AC70026D415 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD5115241B1FFBA900514240 /* Result.framework */; };
141F12361C1C9AC70026D415 /* Result.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = CD5115241B1FFBA900514240 /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -80,6 +83,9 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
0ED17E881E229EC700EC1114 /* QueryParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryParameters.swift; sourceTree = "<group>"; };
0ED17E8A1E22A22900EC1114 /* URLEncodedQueryParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLEncodedQueryParameters.swift; sourceTree = "<group>"; };
0ED17E8D1E22AC8300EC1114 /* URLEncodedQueryParametersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLEncodedQueryParametersTests.swift; sourceTree = "<group>"; };
141F120F1C1C96820026D415 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Base.xcconfig; path = Configurations/Base.xcconfig; sourceTree = "<group>"; };
141F12101C1C96820026D415 /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Configurations/Debug.xcconfig; sourceTree = "<group>"; };
141F12111C1C96820026D415 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Configurations/Release.xcconfig; sourceTree = "<group>"; };
Expand Down Expand Up @@ -156,6 +162,24 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
0ED17E871E229EAC00EC1114 /* QueryParameters */ = {
isa = PBXGroup;
children = (
0ED17E881E229EC700EC1114 /* QueryParameters.swift */,
0ED17E8A1E22A22900EC1114 /* URLEncodedQueryParameters.swift */,
);
name = QueryParameters;
path = APIKit/QueryParameters;
sourceTree = "<group>";
};
0ED17E8C1E22AC5D00EC1114 /* QueryParameters */ = {
isa = PBXGroup;
children = (
0ED17E8D1E22AC8300EC1114 /* URLEncodedQueryParametersTests.swift */,
);
path = QueryParameters;
sourceTree = "<group>";
};
141F120E1C1C96690026D415 /* Configurations */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -224,6 +248,7 @@
7F698E451D9D680C00F1561D /* RequestTests.swift */,
7F698E491D9D680C00F1561D /* SessionCallbackQueueTests.swift */,
7F698E4A1D9D680C00F1561D /* SessionTests.swift */,
0ED17E8C1E22AC5D00EC1114 /* QueryParameters */,
7F698E3B1D9D680C00F1561D /* BodyParametersType */,
7F698E401D9D680C00F1561D /* DataParserType */,
7F698E461D9D680C00F1561D /* SessionAdapterType */,
Expand Down Expand Up @@ -294,6 +319,7 @@
7F7048CB1D9D89BE003C99F6 /* Session.swift */,
7F7048CC1D9D89BE003C99F6 /* Unavailable.swift */,
7F85FB8B1C9D317300CEE132 /* SessionAdapter */,
0ED17E871E229EAC00EC1114 /* QueryParameters */,
7F18BD0D1C972C38003A31DF /* BodyParameters */,
7FA19A441C9CC9A2005D25AE /* DataParser */,
7F18BD161C9730ED003A31DF /* Serializations */,
Expand Down Expand Up @@ -457,12 +483,14 @@
files = (
7F7048D31D9D89BE003C99F6 /* Unavailable.swift in Sources */,
7F7048D11D9D89BE003C99F6 /* Request.swift in Sources */,
0ED17E891E229EC700EC1114 /* QueryParameters.swift in Sources */,
7F7048E81D9D8A08003C99F6 /* DataParser.swift in Sources */,
7F7048CE1D9D89BE003C99F6 /* CallbackQueue.swift in Sources */,
7F7048DE1D9D89FB003C99F6 /* AbstractInputStream.m in Sources */,
7F7048E31D9D89FB003C99F6 /* MultipartFormDataBodyParameters.swift in Sources */,
7F7048F01D9D8A12003C99F6 /* ResponseError.swift in Sources */,
7F7048EA1D9D8A08003C99F6 /* JSONDataParser.swift in Sources */,
0ED17E8B1E22A22900EC1114 /* URLEncodedQueryParameters.swift in Sources */,
7F7048D21D9D89BE003C99F6 /* Session.swift in Sources */,
7F7048E01D9D89FB003C99F6 /* Data+InputStream.swift in Sources */,
7F7048DF1D9D89FB003C99F6 /* BodyParameters.swift in Sources */,
Expand Down Expand Up @@ -491,6 +519,7 @@
7F698E501D9D680C00F1561D /* FormURLEncodedBodyParametersTests.swift in Sources */,
7F698E581D9D680C00F1561D /* RequestTests.swift in Sources */,
ECA8314A1DE4DEBE004EB1B5 /* ProtobufDataParserTests.swift in Sources */,
0ED17E8E1E22AC8300EC1114 /* URLEncodedQueryParametersTests.swift in Sources */,
7F698E5E1D9D680C00F1561D /* TestRequest.swift in Sources */,
7F698E601D9D680C00F1561D /* TestSessionTask.swift in Sources */,
7FA1690D1D9D8C80006C982B /* HTTPStub.swift in Sources */,
Expand Down
7 changes: 7 additions & 0 deletions Sources/APIKit/QueryParameters/QueryParameters.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Foundation

/// `QueryParameters` provides interface to generate HTTP URL query strings.
public protocol QueryParameters {
/// Generate URL query strings.
func encode() -> String?
}
20 changes: 20 additions & 0 deletions Sources/APIKit/QueryParameters/URLEncodedQueryParameters.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Foundation

/// `URLEncodedQueryParameters` serializes form object for HTTP URL query.
public struct URLEncodedQueryParameters: QueryParameters {
/// The parameters to be url encoded.
public let parameters: Any

/// Returns `URLEncodedQueryParameters` that is initialized with parameters.
public init(parameters: Any) {
self.parameters = parameters
}

/// Generate url encoded `String`.
public func encode() -> String? {
guard let parameters = parameters as? [String: Any], !parameters.isEmpty else {
return nil
}
return URLEncodedSerialization.string(from: parameters)
}
}
12 changes: 6 additions & 6 deletions Sources/APIKit/Request.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public protocol Request {
/// The actual parameters for the URL query. The values of this property will be escaped using `URLEncodedSerialization`.
/// If this property is not implemented and `method.prefersQueryParameter` is `true`, the value of this property
/// will be computed from `parameters`.
var queryParameters: [String: Any]? { get }
var queryParameters: QueryParameters? { get }

/// The actual parameters for the HTTP body. If this property is not implemented and `method.prefersQueryParameter` is `false`,
/// the value of this property will be computed from `parameters` using `JSONBodyParameters`.
Expand Down Expand Up @@ -66,12 +66,12 @@ public extension Request {
return nil
}

public var queryParameters: [String: Any]? {
guard let parameters = parameters as? [String: Any], method.prefersQueryParameters else {
public var queryParameters: QueryParameters? {
guard let parameters = parameters, method.prefersQueryParameters else {
return nil
}

return parameters
return URLEncodedQueryParameters(parameters: parameters)
}

public var bodyParameters: BodyParameters? {
Expand Down Expand Up @@ -111,8 +111,8 @@ public extension Request {

var urlRequest = URLRequest(url: url)

if let queryParameters = queryParameters, !queryParameters.isEmpty {
components.percentEncodedQuery = URLEncodedSerialization.string(from: queryParameters)
if let queryString = queryParameters?.encode(), !queryString.isEmpty {
components.percentEncodedQuery = queryString
}

if let bodyParameters = bodyParameters {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import XCTest
import APIKit

class URLEncodedQueryParametersTests: XCTestCase {
func testURLEncodedSuccess() {
let object: [String: Any] = ["foo": "string", "bar": 1, "q": "こんにちは"]
let parameters = URLEncodedQueryParameters(parameters: object)
guard let query = parameters.encode() else {
XCTFail()
return
}

let items = query.components(separatedBy: "&")
XCTAssertEqual(items.count, 3)
XCTAssertTrue(items.contains("foo=string"))
XCTAssertTrue(items.contains("bar=1"))
XCTAssertTrue(items.contains("q=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF"))
}
}

0 comments on commit 263ba3f

Please sign in to comment.