Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
267 changes: 267 additions & 0 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ let package = Package(
),
],
dependencies: [
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.25.0"),
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.28.0"),
.package(url: "https://github.com/swiftlang/swift-syntax.git", "600.0.0" ..< "605.0.0"),
.package(url: "https://github.com/pointfreeco/swift-macro-testing.git", from: "0.7.0"),
.package(
url: "https://github.com/apple/swift-configuration.git",
from: "1.0.2",
traits: []
),
.package(url: "https://github.com/apple/swift-service-context.git", from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
Expand All @@ -32,7 +31,6 @@ let package = Package(
name: "Nectar",
dependencies: [
.product(name: "Hummingbird", package: "hummingbird"),
.product(name: "ServiceContextModule", package: "swift-service-context"),
"NectarMacros"
],
swiftSettings: [
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,16 @@ struct CommentEndpointGroup: EndpointGroup {
func getComments(id: UUID) -> String {
"id: \(id.uuidString)"
}

func addMiddlewares<C: RequestContext>(to group: RouterGroup<C>) -> RouterGroup<C> {
group.addMiddleware {
LogRequestMiddleware(.info)
}
}
}

// register:
router.registerNectarApp(AppEntry())
try router.registerNectarApp(AppEntry())
```

## Goal
Expand All @@ -69,5 +75,6 @@ Nectar combines **Swift Macros** and **Result Builders** to extract parameters a
* **Optional parameters** are automatically resolved as **query parameters**.
* Arguments typed as `Request` or `any RequestContext` will seamlessly receive the raw request or request context.
* **Path Customization:** Override or explicitly specify structural sub-paths using the `pattern` argument inside the route macros (e.g., `@GET(pattern: ":id/activity")`).
* On startup every endpoint is checked for using path parameters thar aren't declared.


4 changes: 2 additions & 2 deletions Scripts/format.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cd "$(dirname "$0")"/../ || exit 1

if [ -z "$1" ]; then
swiftformat . --exclude Sources/ULID/*,Tests/ULIDTests/*,Sources/VeinCore/VeinCore.docc/*,Sources/VeinSwiftUI/VeinSwiftUI.docc/*,Sources/VeinSCUI/VeinSCUI.docc/*
swiftformat .
else
swiftformat "$1"
fi
fi
3 changes: 3 additions & 0 deletions Sources/Nectar/Endpoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@
public struct Endpoint {
let partialPath: String
let httpMethod: HTTPMethod
let pathParams: [String]

let handler: @Sendable (Request, any RequestContext) async throws -> Response

public init(
partialPath: String,
httpMethod: HTTPMethod,
pathParams: [String],
handler: @Sendable @escaping (Request, any RequestContext) async throws -> Response
) {
self.partialPath = partialPath
self.httpMethod = httpMethod
self.handler = handler
self.pathParams = pathParams
}
}
24 changes: 24 additions & 0 deletions Sources/Nectar/EndpointAdditionError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// ===----------------------------------------------------------------------===
//
// This source file is part of the Nectar open source project
//
// Copyright (c) 2026 Mia Koring.
//
// Licensed under Apache License v2.0
//
// ===----------------------------------------------------------------------===

import Foundation

public enum EndpointAdditionError: Error {
case missingPathParameter(String, String)
}

extension EndpointAdditionError: LocalizedError {
public var errorDescription: String? {
switch self {
case .missingPathParameter(let string, let uri):
"The required path parameter '\(string)' is not part of the URI '\(uri)'"
}
}
}
4 changes: 2 additions & 2 deletions Sources/Nectar/EndpointBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

@resultBuilder
public struct EndpointBuilder {
public static func buildBlock(_ components: EndpointDeclaration...) -> [Endpoint] {
return components.reduce(into: [Endpoint]()) { $0 += $1.endpoints }
public static func buildBlock(_ components: EndpointGroup...) -> [EndpointGroup] {
return components.reduce(into: [EndpointGroup]()) { $0.append($1) }
}
}
6 changes: 0 additions & 6 deletions Sources/Nectar/EndpointDeclaration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,3 @@
// Licensed under Apache License v2.0
//
// ===----------------------------------------------------------------------===

public protocol EndpointDeclaration {
var partialName: String { get }

var endpoints: [Endpoint] { get }
}
Loading
Loading