Skip to content

Commit

Permalink
Remove GIT and add support for all existing request methods
Browse files Browse the repository at this point in the history
  • Loading branch information
AvdLee committed Jul 9, 2022
1 parent 384586b commit 44065a6
Show file tree
Hide file tree
Showing 158 changed files with 256 additions and 5,704 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "AppStoreConnect-Swift-SDK-Tests"
BuildableName = "AppStoreConnect-Swift-SDK-Tests"
BlueprintName = "AppStoreConnect-Swift-SDK-Tests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
Expand Down
10 changes: 4 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// swift-tools-version:5.5
// We're hiding dev, test, and danger dependencies with // dev to make sure they're not fetched by users of this package.
// swift-tools-version:5.6
import PackageDescription

let package = Package(
Expand All @@ -12,14 +11,13 @@ let package = Package(
.library(name: "AppStoreConnect-Swift-SDK", targets: ["AppStoreConnect-Swift-SDK"])
],
dependencies: [
.package(url: "https://github.com/CreateAPI/URLQueryEncoder.git", from: "0.2.0"),
.package(url: "https://github.com/kean/Get.git", from: "0.8.0")
.package(url: "https://github.com/CreateAPI/URLQueryEncoder.git", from: "0.2.0")
],
targets: [
// dev .testTarget(name: "AppStoreConnect-Swift-SDK-Tests", dependencies: ["AppStoreConnect-Swift-SDK"], path: "Tests", exclude: ["LinuxMain.swift"]),
.testTarget(name: "AppStoreConnect-Swift-SDK-Tests", dependencies: ["AppStoreConnect-Swift-SDK"], path: "Tests"),
.target(
name: "AppStoreConnect-Swift-SDK",
dependencies: ["URLQueryEncoder", "Get"],
dependencies: ["URLQueryEncoder"],
path: "Sources",
exclude: ["OpenAPI/app_store_connect_api_1.8_openapi.json"])
]
Expand Down
229 changes: 101 additions & 128 deletions Sources/APIProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,80 +113,63 @@ public final class APIProvider {
/// Handles URLRequest execution
private let requestExecutor: RequestExecutor

private let client: APIClient
/// The JSON encoder used to encode request parameters.
private let encoder: JSONEncoder

/// Creates a new APIProvider instance which can be used to perform API Requests to the App Store Connect API.
///
/// - Parameters:
/// - configuration: The configuration needed to set up the API Provider including all needed information for performing API requests.
/// - requestExecutor: An instance conforming to the RequestExecutor protocol for executing URLRequest
public init(configuration: APIConfiguration, requestExecutor: RequestExecutor = DefaultRequestExecutor()) {
let requestAuthenticator = JWTRequestsAuthenticator(apiConfiguration: configuration)
client = APIClient(baseURL: URL(string: "https://api.appstoreconnect.apple.com")!) {
$0.delegate = requestAuthenticator
}

self.configuration = configuration
self.requestExecutor = requestExecutor
self.requestsAuthenticator = requestAuthenticator
}

public func request<Response: Decodable>(_ request: Request<Response>) async throws -> Response {
let response = try await client.send(request)
return response.value
self.requestsAuthenticator = JWTRequestsAuthenticator(apiConfiguration: configuration)
self.encoder = JSONEncoder()
self.encoder.dateEncodingStrategy = .iso8601
}

/// Performs a data request to the given API endpoint
///
/// - Parameters:
/// - endpoint: The API endpoint to request.
/// - completion: The completion callback which will be called on completion containing the result.
// public func request(_ endpoint: APIEndpoint<Void>, completion: @escaping RequestCompletionHandler<Void>) {
// guard let request = try? requestsAuthenticator.adapt(endpoint.asURLRequest()) else {
// completion(.failure(Error.requestGeneration))
// return
// }
//
// requestExecutor.execute(request) { completion(self.mapVoidResponse($0)) }
// }
public func request(_ request: Request<Void>, completion: @escaping RequestCompletionHandler<Void>) {
guard let request = try? requestsAuthenticator.adapt(request.asURLRequest(encoder: encoder)) else {
completion(.failure(Error.requestGeneration))
return
}

requestExecutor.execute(request) { completion(self.mapVoidResponse($0)) }
}

/// Performs a data request to the given API endpoint
///
/// - Parameters:
/// - endpoint: The API endpoint to request.
/// - completion: The completion callback which will be called on completion containing the result.
// public func request<T: Decodable>(_ endpoint: APIEndpoint<T>, completion: @escaping RequestCompletionHandler<T>) {
// guard let request = try? requestsAuthenticator.adapt(endpoint.asURLRequest()) else {
// completion(.failure(Error.requestGeneration))
// return
// }
//
// requestExecutor.execute(request) { completion(self.mapResponse($0)) }
// }
public func request<T: Decodable>(_ request: Request<T>, completion: @escaping RequestCompletionHandler<T>) {
guard let request = try? requestsAuthenticator.adapt(request.asURLRequest(encoder: encoder)) else {
completion(.failure(Error.requestGeneration))
return
}

requestExecutor.execute(request) { completion(self.mapResponse($0)) }
}

/// Performs a download request to the given API endpoint
///
/// - Parameters:
/// - endpoint: The API endpoint to request.
/// - completion: The completion callback which will be called on completion containing the result.
// public func download<T: Decodable>(_ endpoint: APIEndpoint<T>, completion: @escaping RequestCompletionHandler<URL>) {
// guard let request = try? requestsAuthenticator.adapt(endpoint.asURLRequest()) else {
// completion(.failure(Error.requestGeneration))
// return
// }
//
// requestExecutor.download(request) { completion(self.mapResponse($0)) }
// }

// /// Performs a data request to the given ResourceLinks
// ///
// /// - Parameters:
// /// - resourceLinks: The resourceLinks to request.
// /// - completion: The completion callback which will be called on completion containing the result.
// public func request<T: Decodable>(_ resourceLinks: ResourceLinks<T>, completion: @escaping RequestCompletionHandler<T>) {
//
// requestExecutor.retrieve(resourceLinks.`self`) { completion(self.mapResponse($0)) }
// }
public func download<T: Decodable>(_ request: Request<T>, completion: @escaping RequestCompletionHandler<URL>) {
guard let request = try? requestsAuthenticator.adapt(request.asURLRequest(encoder: encoder)) else {
completion(.failure(Error.requestGeneration))
return
}

requestExecutor.download(request) { completion(self.mapResponse($0)) }
}
}

// MARK: - async/await
Expand All @@ -195,41 +178,31 @@ extension APIProvider {
///
/// - Parameters:
/// - endpoint: The API endpoint to request.
// public func request(_ endpoint: APIEndpoint<Void>) async throws {
// try await withCheckedThrowingContinuation { continuation in
// request(endpoint, completion: continuation.resume(with:))
// }
// }
public func request(_ endpoint: Request<Void>) async throws {
try await withCheckedThrowingContinuation { continuation in
request(endpoint, completion: continuation.resume(with:))
}
}

/// Performs a data request to the given API endpoint
///
/// - Parameters:
/// - endpoint: The API endpoint to request.
// public func request<T>(_ endpoint: APIEndpoint<T>) async throws -> T where T: Decodable {
// try await withCheckedThrowingContinuation { continuation in
// request(endpoint, completion: continuation.resume(with:))
// }
// }
public func request<T>(_ endpoint: Request<T>) async throws -> T where T: Decodable {
try await withCheckedThrowingContinuation { continuation in
request(endpoint, completion: continuation.resume(with:))
}
}

/// Performs a download request to the given API endpoint
///
/// - Parameters:
/// - endpoint: The API endpoint to request.
// public func download<T>(_ endpoint: APIEndpoint<T>) async throws -> URL where T: Decodable {
// try await withCheckedThrowingContinuation { continuation in
// download(endpoint, completion: continuation.resume(with:))
// }
// }

/// Performs a data request to the given ResourceLinks
///
/// - Parameters:
/// - resourceLinks: The resourceLinks to request.
// public func request<T>(_ resourceLinks: ResourceLinks<T>) async throws -> T where T: Decodable {
// try await withCheckedThrowingContinuation { continuation in
// request(resourceLinks, completion: continuation.resume(with:))
// }
// }
public func download<T>(_ endpoint: Request<T>) async throws -> URL where T: Decodable {
try await withCheckedThrowingContinuation { continuation in
download(endpoint, completion: continuation.resume(with:))
}
}
}

// MARK: - Private
Expand All @@ -239,62 +212,62 @@ private extension APIProvider {
///
/// - Parameter result: A result type containing either the network response or an error
/// - Returns: A result type containing either the decoded type or an error
// func mapResponse<T: Decodable>(_ result: Result<Response<Data>, Swift.Error>) -> Result<T, Swift.Error> {
// switch result {
// case .success(let response):
// guard let data = response.data, 200..<300 ~= response.statusCode else {
// return .failure(Error.requestFailure(response.statusCode, response.data))
// }
//
// if let data = data as? T {
// return .success(data)
// }
//
// do {
// let decodedValue = try Self.jsonDecoder.decode(T.self, from: data)
// return .success(decodedValue)
// } catch {
// return .failure(Error.decodingError(error, data))
// }
// case .failure(let error):
// return .failure(Error.requestExecutorError(error))
// }
// }
//
// /// Maps a network response to a (void) result type
// ///
// /// - Parameter result: A result type containing either the network response or an error
// /// - Returns: A result type containing either void or an error
// func mapVoidResponse(_ result: Result<Response<Data>, Swift.Error>) -> Result<Void, Swift.Error> {
// switch result {
// case .success(let response):
// guard 200..<300 ~= response.statusCode else {
// return .failure(Error.requestFailure(response.statusCode, response.data))
// }
//
// return .success(())
// case .failure(let error):
// return .failure(Error.requestExecutorError(error))
// }
// }
//
// /// Maps a download response to a URL type
// ///
// /// - Parameter result: A result type containing either the network response or an error
// /// - Returns: A result type containing either the decoded type or an error
// func mapResponse(_ result: Result<Response<URL>, Swift.Error>) -> Result<URL, Swift.Error> {
// switch result {
// case .success(let response):
// guard 200..<300 ~= response.statusCode else {
// return .failure(Error.requestFailure(response.statusCode, nil))
// }
// if let data = response.data {
// return .success(data)
// }
// return .failure(Error.downloadError)
// case .failure(let error):
// return .failure(Error.requestExecutorError(error))
// }
// }
func mapResponse<T: Decodable>(_ result: Result<Response<Data>, Swift.Error>) -> Result<T, Swift.Error> {
switch result {
case .success(let response):
guard let data = response.data, 200..<300 ~= response.statusCode else {
return .failure(Error.requestFailure(response.statusCode, response.data, response.requestURL))
}

if let data = data as? T {
return .success(data)
}

do {
let decodedValue = try Self.jsonDecoder.decode(T.self, from: data)
return .success(decodedValue)
} catch {
return .failure(Error.decodingError(error, data))
}
case .failure(let error):
return .failure(Error.requestExecutorError(error))
}
}

/// Maps a network response to a (void) result type
///
/// - Parameter result: A result type containing either the network response or an error
/// - Returns: A result type containing either void or an error
func mapVoidResponse(_ result: Result<Response<Data>, Swift.Error>) -> Result<Void, Swift.Error> {
switch result {
case .success(let response):
guard 200..<300 ~= response.statusCode else {
return .failure(Error.requestFailure(response.statusCode, response.data, response.requestURL))
}

return .success(())
case .failure(let error):
return .failure(Error.requestExecutorError(error))
}
}

/// Maps a download response to a URL type
///
/// - Parameter result: A result type containing either the network response or an error
/// - Returns: A result type containing either the decoded type or an error
func mapResponse(_ result: Result<Response<URL>, Swift.Error>) -> Result<URL, Swift.Error> {
switch result {
case .success(let response):
guard 200..<300 ~= response.statusCode else {
return .failure(Error.requestFailure(response.statusCode, nil, response.requestURL))
}
if let data = response.data {
return .success(data)
}
return .failure(Error.downloadError)
case .failure(let error):
return .failure(Error.requestExecutorError(error))
}
}

}
16 changes: 2 additions & 14 deletions Sources/DefaultRequestExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,6 @@ public final class DefaultRequestExecutor: RequestExecutor {
}.resume()
}

/// Retrieves a resource and delivers an async result
///
/// - Parameters:
/// - url: The URL where the resource is located
/// - completion: A result type containing eiter the response or an error
public func retrieve(_ url: URL, completion: @escaping (Result<Response<Data>, Swift.Error>) -> Void) {
urlSession.dataTask(with: url) { data, response, error in
completion(mapResponse(data: data, urlResponse: response, error: error))
}.resume()
}

/// Download report as file
///
/// - Parameters:
Expand All @@ -53,7 +42,6 @@ public final class DefaultRequestExecutor: RequestExecutor {
completion(mapResponse(fileUrl: fileUrl, urlResponse: response, error: error))
}.resume()
}

}

// MARK: - Private
Expand All @@ -73,7 +61,7 @@ func mapResponse(data: Data?, urlResponse: URLResponse?, error: Error?) -> Resul
return .failure(DefaultRequestExecutor.Error.unknownResponseType)
}

return .success(.init(statusCode: httpUrlResponse.statusCode, data: data))
return .success(.init(requestURL: httpUrlResponse.url, statusCode: httpUrlResponse.statusCode, data: data))
}
}

Expand All @@ -92,6 +80,6 @@ func mapResponse(fileUrl: URL?, urlResponse: URLResponse?, error: Error?) -> Res
return .failure(DefaultRequestExecutor.Error.unknownResponseType)
}

return .success(.init(statusCode: httpUrlResponse.statusCode, data: fileUrl))
return .success(.init(requestURL: httpUrlResponse.url, statusCode: httpUrlResponse.statusCode, data: fileUrl))
}
}
Loading

0 comments on commit 44065a6

Please sign in to comment.