Skip to content

Commit

Permalink
Merge pull request #1 from pixel-foundry/endpoint-builder
Browse files Browse the repository at this point in the history
Implement initial EndpointBuilder
  • Loading branch information
hallee authored Jan 28, 2024
2 parents a64f55b + dc4f1d9 commit fdd2ec4
Show file tree
Hide file tree
Showing 15 changed files with 568 additions and 21 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ playground.xcworkspace
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
Packages/
Package.pins
Package.resolved
*.xcodeproj

# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
Expand Down
4 changes: 3 additions & 1 deletion .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ opt_in_rules:
- contains_over_filter_is_empty
- contains_over_first_not_nil
- contains_over_range_nil_comparison
- convenience_type
- empty_count
- empty_string
- explicit_init
Expand All @@ -34,6 +33,9 @@ opt_in_rules:
- untyped_error_in_catch
- vertical_parameter_alignment_on_call
- yoda_condition
excluded:
- .build
- .swiftpm
indentation_width:
include_comments: false
line_length:
Expand Down
59 changes: 59 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"pins" : [
{
"identity" : "routing-kit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/routing-kit",
"state" : {
"revision" : "2a92a7eac411a82fb3a03731be5e76773ebe1b3e",
"version" : "4.9.0"
}
},
{
"identity" : "swift-http-types",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-http-types",
"state" : {
"revision" : "12358d55a3824bd5fed310b999ea8cf83a9a1a65",
"version" : "1.0.3"
}
},
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "e97a6fcb1ab07462881ac165fdbb37f067e205d5",
"version" : "1.5.4"
}
},
{
"identity" : "swift-macro-testing",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-macro-testing",
"state" : {
"revision" : "10dcef36314ddfea6f60442169b0b320204cbd35",
"version" : "0.2.2"
}
},
{
"identity" : "swift-snapshot-testing",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-snapshot-testing",
"state" : {
"revision" : "8e68404f641300bfd0e37d478683bb275926760c",
"version" : "1.15.2"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "64889f0c732f210a935a0ad7cda38f77f876262d",
"version" : "509.1.1"
}
}
],
"version" : 2
}
39 changes: 34 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,42 @@
// swift-tools-version:5.8
// swift-tools-version:5.9
import CompilerPluginSupport
import PackageDescription

let package = Package(
name: "SwiftPackage",
name: "endpoint-builder",
products: [
.library(name: "SwiftPackage", targets: ["SwiftPackage"])
.library(name: "EndpointBuilder", targets: ["EndpointBuilder"])
],
dependencies: [
.package(url: "https://github.com/apple/swift-http-types", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"),
.package(url: "https://github.com/pointfreeco/swift-macro-testing", from: "0.2.0"),
.package(url: "https://github.com/vapor/routing-kit", from: "4.9.0")
],
targets: [
.target(name: "SwiftPackage"),
.testTarget(name: "Tests", dependencies: ["SwiftPackage"])
.target(
name: "EndpointBuilder",
dependencies: [
.byName(name: "EndpointBuilderMacros"),
.product(name: "HTTPTypes", package: "swift-http-types"),
.product(name: "RoutingKit", package: "routing-kit")
]
),
.testTarget(name: "EndpointBuilderTests", dependencies: ["EndpointBuilder"]),
.macro(
name: "EndpointBuilderMacros",
dependencies: [
.product(name: "RoutingKit", package: "routing-kit"),
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
]
),
.testTarget(
name: "EndpointBuilderMacrosTests",
dependencies: [
.byName(name: "EndpointBuilderMacros"),
.product(name: "MacroTesting", package: "swift-macro-testing")
]
)
]
)
8 changes: 1 addition & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
# Swift Package Repository Template

This is a project template for Swift packages.

* Sensible `.gitignore`
* `.swiftlint.yml` for linting
* `.editorconfig` enforcing tabs with a size of 2.
# Endpoint Builder
23 changes: 23 additions & 0 deletions Sources/EndpointBuilder/Authorization.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Foundation

/// HTTP authorization schemes
public enum Authorization: Sendable, Hashable {

/// Basic authorization
case basic(username: String, password: String)

/// Bearer authorization
case bearer(token: String)

/// HTTP header string value
public var headerValue: String {
switch self {
case let .basic(username, password):
let encoded = Data("\(username):\(password)".utf8).base64EncodedString()
return "Basic \(encoded)"
case let .bearer(token):
return "Bearer \(token)"
}
}

}
45 changes: 45 additions & 0 deletions Sources/EndpointBuilder/Endpoint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Foundation
import HTTPTypes
import RoutingKit

/// Describes an API endpoint
public protocol Endpoint: Sendable {

associatedtype BodyContent: Codable
associatedtype Response: Codable

/// The path components for this endpoint
static var path: [PathComponent] { get }

/// The HTTP method for this endpoint
static var httpMethod: HTTPRequest.Method { get }

/// The response type of this endpoint
static var responseType: Response.Type { get }

/// Authorization headers to be sent along with the request
var authorization: Authorization? { get }

/// Request body content
var body: BodyContent { get }

/// The URL path for this endpoint
var path: String { get }

}

public extension Endpoint {

var authorization: Authorization? {
nil
}

var body: Never {
fatalError()
}

static var responseType: Never.Type {
fatalError()
}

}
10 changes: 10 additions & 0 deletions Sources/EndpointBuilder/EndpointMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import HTTPTypes
import RoutingKit

/// Conforms a type to the `Endpoint` protocol.
///
/// Generates a `path` string for the given path components,
/// along with a helper type for initializing any path parameters.
@attached(extension, conformances: Endpoint)
@attached(member, names: named(PathParameters), named(pathParameters), named(path))
public macro Endpoint() = #externalMacro(module: "EndpointBuilderMacros", type: "EndpointMacro")
13 changes: 13 additions & 0 deletions Sources/EndpointBuilder/Never+Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Foundation

extension Never: Codable {

public init(from decoder: Decoder) throws {
throw DecodingError.dataCorrupted(
DecodingError.Context(codingPath: [], debugDescription: "Never values cannot be decoded.")
)
}

public func encode(to encoder: Encoder) throws {}

}
Loading

0 comments on commit fdd2ec4

Please sign in to comment.