Nectar is a thin, type-safe, declarative router layer built on top of the Hummingbird server framework. It brings high-ergonomics, controller-style endpoint definitions to server-side Swift without sacrificing performance.
import Nectar
struct AppEntry: NectarApp {
var endpoints: [any EndpointGroup] {
UserEndpointGroup()
}
}
@Endpoints
struct UserEndpointGroup: EndpointGroup {
let partialName = "users"
var subgroups: [any EndpointGroup] {
PathExtension(":id") {
CommentEndpointGroup()
}
}
@GET
func getUser(id: UUID, otherThing: UUID?) throws -> String {
return "id: \(id), otherThing: \(otherThing)"
}
@GET(pattern: ":id/activity")
func getUserActivity(id: UUID) -> String {
return "Activity: \(id.uuidString)"
}
@POST
func createUser(body: UserCreationDTO) -> String {
return "name: \(body.name)\nemail: \(body.email)\npassword: \(body.password)"
}
}
@Endpoints
struct CommentEndpointGroup: EndpointGroup {
let partialName: String = "comments"
@GET(pattern: "")
func getComments(id: UUID) -> String {
"id: \(id.uuidString)"
}
func addMiddlewares<C: RequestContext>(to group: RouterGroup<C>) -> RouterGroup<C> {
group.addMiddleware {
LogRequestMiddleware(.info)
}
}
}
// register:
try router.registerNectarApp(AppEntry())- Low visual nesting: Avoid the deeply nested structural blocks typical of standard router trees.
- Zero Runtime Overhead: All routing maps down exactly to standard Hummingbird router.get(...),... calls during application startup. Request handling is fast and memory-efficient.
- Non-Opinionated & Non-Intrusive: Nectar is a light layer. It doesn't alter your database, middleware, or application setup—it simply registers routes to your existing Hummingbird router. (for now)
Nectar combines Swift Macros and Result Builders to extract parameters and register endpoints cleanly:
- Return Types: Functions can return any type conforming to Hummingbird's
ResponseGenerator. - Concurrency: Fully supports native
asyncandthrowsexecution. - Auto-Body Decoding: Name a function argument
bodyto automatically decode the incoming request payload usingCodable. - Parameter Resolution:
- Non-optional parameters are automatically resolved as path parameters.
- Optional parameters are automatically resolved as query parameters.
- Arguments typed as
Requestorany RequestContextwill seamlessly receive the raw request or request context.
- Path Customization: Override or explicitly specify structural sub-paths using the
patternargument inside the route macros (e.g.,@GET(pattern: ":id/activity")). - On startup every endpoint is checked for using path parameters thar aren't declared.