Skip to content

Commit

Permalink
Add query parameters support
Browse files Browse the repository at this point in the history
  • Loading branch information
ugoArangino committed Nov 23, 2023
1 parent fac51e8 commit 8a9e217
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 10 deletions.
11 changes: 11 additions & 0 deletions Example/Example/ExampleTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ extension ExampleTarget: TargetType {
}
}

var queryParameters: [String: String]? {
switch self {
case .gitHubOrganizations:
[
"per_page": "5",
]
case .httpbinPOST:
nil
}
}

var method: HTTPMethod {
switch self {
case .gitHubOrganizations:
Expand Down
18 changes: 14 additions & 4 deletions Sources/SwiftAPIGate/APIGate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,25 @@ public final class APIGate<Target: TargetType>: APIGateType {
let updatedTarget: TargetType = try await middleware?.target(target) ?? target
let baseURL = updatedTarget.baseURL
let path = updatedTarget.path
let queryParameters = updatedTarget.queryParameters
let method = updatedTarget.method
let validationType = updatedTarget.validationType
let headers = updatedTarget.headers

let requestURL: URL = if let path {
baseURL.appendingPathComponent(path)
} else {
baseURL
guard var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: false) else {
throw URLError(.badURL)
}
if let path = path {
components.path = path
}
if let queryParameters = queryParameters {
components.queryItems = queryParameters.map { URLQueryItem(name: $0.key, value: $0.value) }
}

guard let requestURL = components.url else {
throw URLError(.badURL)
}

var request = URLRequest(url: requestURL)
request.httpMethod = method.rawValue
headers?.forEach {
Expand Down
5 changes: 5 additions & 0 deletions Sources/SwiftAPIGate/AbstractTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Foundation
public struct AbstractTarget: TargetType {
public let baseURL: URL
public let path: String?
public let queryParameters: [String: String]?
public let method: HTTPMethod
public let validationType: ValidationType
public let headers: [String: String]?
Expand All @@ -11,13 +12,15 @@ public struct AbstractTarget: TargetType {
public init(
baseURL: URL,
path: String?,
queryParameters: [String: String]? = nil,
method: HTTPMethod,
validationType: ValidationType = .none,
headers: [String: String]? = nil,
body: Data?
) {
self.baseURL = baseURL
self.path = path
self.queryParameters = queryParameters
self.method = method
self.validationType = validationType
self.headers = headers
Expand All @@ -28,6 +31,7 @@ public struct AbstractTarget: TargetType {
from target: TargetType,
withBaseURL baseURL: URL? = nil,
withPath path: String? = nil,
withQueryParameters queryParameters: [String: String]? = nil,
withMethod method: HTTPMethod? = nil,
withValidationType validationType: ValidationType? = nil,
withHeaders headers: [String: String]? = nil,
Expand All @@ -36,6 +40,7 @@ public struct AbstractTarget: TargetType {
self.init(
baseURL: baseURL ?? target.baseURL,
path: path ?? target.path,
queryParameters: queryParameters ?? target.queryParameters,
method: method ?? target.method,
validationType: validationType ?? target.validationType,
headers: headers ?? target.headers,
Expand Down
3 changes: 3 additions & 0 deletions Sources/SwiftAPIGate/TargetType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ public protocol TargetType: CustomStringConvertible {
/// The path to be appended to `baseURL` to form the full `URL`.
var path: String? { get }

/// The query parameters to be appended to the `URL`.
var queryParameters: [String: String]? { get }

/// The HTTP method used.
var method: HTTPMethod { get }

Expand Down
30 changes: 24 additions & 6 deletions Tests/SwiftAPIGateTests/APIGateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,31 @@ final class APIGateTests: XCTestCase {
response: .init(url: Fixture.url, mimeType: nil, expectedContentLength: 0, textEncodingName: nil)
)

// Act
let apiResponse = try await sut.request(.userProfile("test"))

// Assert
XCTAssertEqual(try XCTUnwrap(apiResponse.data), fakeData)
XCTAssertEqual(sessionMock.dataInvocations.map(\.url), [
.init(string: "https://api.github.com/users/test")!,
])
}

func testLoadWithQueryParameters() async throws {
// Arrange
let fakeData = #function.data(using: .utf8)
sessionMock.setDataValue(
data: fakeData,
response: .init(url: Fixture.url, mimeType: nil, expectedContentLength: 0, textEncodingName: nil)
)

// Act
let apiResponse = try await sut.request(.organizations)

// Assert
XCTAssertEqual(try XCTUnwrap(apiResponse.data), fakeData)
XCTAssertEqual(sessionMock.dataInvocations, [
.init(url: .init(string: "https://api.github.com/organizations")!),
XCTAssertEqual(sessionMock.dataInvocations.map(\.url), [
.init(string: "https://api.github.com/organizations?per_page=5")!,
])
}

Expand Down Expand Up @@ -88,8 +106,8 @@ final class APIGateTests: XCTestCase {

// Assert
XCTAssertEqual(decodedResponse, exampleDecodable)
XCTAssertEqual(sessionMock.dataInvocations, [
.init(url: .init(string: "https://api.github.com/organizations")!),
XCTAssertEqual(sessionMock.dataInvocations.map(\.url), [
.init(string: "https://api.github.com/organizations?per_page=5")!,
])
}

Expand Down Expand Up @@ -130,8 +148,8 @@ final class APIGateTests: XCTestCase {

// Assert
await XCTAssertThrowsAsyncError(try await act())
XCTAssertEqual(sessionMock.dataInvocations, [
.init(url: .init(string: "https://api.github.com/organizations")!),
XCTAssertEqual(sessionMock.dataInvocations.map(\.url), [
.init(string: "https://api.github.com/organizations?per_page=5")!,
])
}
}
11 changes: 11 additions & 0 deletions Tests/SwiftAPIGateTests/Fixtures/GitHubTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ extension GitHubTarget: TargetType {
}
}

var queryParameters: [String: String]? {
switch self {
case .organizations:
[
"per_page": "5",
]
default:
nil
}
}

var method: HTTPMethod {
switch self {
case .organizations:
Expand Down

0 comments on commit 8a9e217

Please sign in to comment.