114 lines
3.3 KiB
Swift
114 lines
3.3 KiB
Swift
//
|
|
// Resource.swift
|
|
// Buildkite
|
|
//
|
|
// Created by Aaron Sky on 3/22/20.
|
|
// Copyright © 2020 Aaron Sky. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
#if canImport(FoundationNetworking)
|
|
import FoundationNetworking
|
|
#endif
|
|
|
|
/// Error thrown when the ``Resource`` provided to the client is incompatible
|
|
/// with the client's supported API versions.
|
|
public enum ResourceError: Error, Equatable {
|
|
case incompatibleVersion(APIVersion)
|
|
}
|
|
|
|
/// Resource describes an endpoint on any of Buildkite's APIs. Do not implement this type.
|
|
public protocol Resource: Sendable {
|
|
/// The input type.
|
|
associatedtype Body = Void
|
|
/// The return type.
|
|
associatedtype Content = Void
|
|
|
|
/// The API and version for the resource.
|
|
var version: APIVersion { get }
|
|
/// The path to the resource.
|
|
var path: String { get }
|
|
/// An instance of the input type to be served with the request.
|
|
var body: Body { get }
|
|
/// Transform the given URLRequest to fit the resource.
|
|
func transformRequest(_ request: inout URLRequest)
|
|
}
|
|
|
|
extension Resource {
|
|
public var version: APIVersion {
|
|
APIVersion.REST.v2
|
|
}
|
|
|
|
public func transformRequest(_ request: inout URLRequest) {}
|
|
}
|
|
|
|
extension Resource where Body == Void {
|
|
public var body: Body {
|
|
()
|
|
}
|
|
}
|
|
|
|
/// A specialization of ``Resource`` that supports pagination.
|
|
public protocol PaginatedResource: Resource where Content: Decodable {}
|
|
|
|
extension URLRequest {
|
|
init<R: Resource>(
|
|
_ resource: R,
|
|
configuration: Configuration,
|
|
tokens: TokenProvider?
|
|
) async throws {
|
|
let version = resource.version
|
|
guard
|
|
version == configuration.version
|
|
|| version == configuration.graphQLVersion
|
|
|| version == configuration.agentVersion
|
|
|| version == configuration.testAnalyticsVersion
|
|
else {
|
|
throw ResourceError.incompatibleVersion(version)
|
|
}
|
|
|
|
let url = version.url(for: resource.path)
|
|
var request = URLRequest(url: url)
|
|
await configuration.transformRequest(&request, tokens: tokens, version: version)
|
|
resource.transformRequest(&request)
|
|
|
|
self = request
|
|
}
|
|
|
|
init<R: Resource>(
|
|
_ resource: R,
|
|
configuration: Configuration,
|
|
tokens: TokenProvider?,
|
|
encoder: JSONEncoder
|
|
) async throws where R.Body: Encodable {
|
|
try await self.init(resource, configuration: configuration, tokens: tokens)
|
|
httpBody = try encoder.encode(resource.body)
|
|
}
|
|
|
|
init<R: Resource & PaginatedResource>(
|
|
_ resource: R,
|
|
configuration: Configuration,
|
|
tokens: TokenProvider?,
|
|
pageOptions: PageOptions? = nil
|
|
) async throws {
|
|
try await self.init(resource, configuration: configuration, tokens: tokens)
|
|
if let options = pageOptions {
|
|
appendPageOptions(options)
|
|
}
|
|
}
|
|
|
|
init<R: Resource & PaginatedResource>(
|
|
_ resource: R,
|
|
configuration: Configuration,
|
|
tokens: TokenProvider?,
|
|
encoder: JSONEncoder,
|
|
pageOptions: PageOptions? = nil
|
|
) async throws where R.Body: Encodable {
|
|
try await self.init(resource, configuration: configuration, tokens: tokens, encoder: encoder)
|
|
if let options = pageOptions {
|
|
appendPageOptions(options)
|
|
}
|
|
}
|
|
}
|