Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preview HTTPHandler Macro (@HTTPRoute / @JSONRoute) #73

Merged
merged 4 commits into from
Oct 29, 2023

Conversation

swhitty
Copy link
Owner

@swhitty swhitty commented Oct 29, 2023

An experimental preview of @HTTPRoute and @JSONRoute to annotate functions with routes.
The annotations are implemented via SE-0389 Attached Macros available in Swift 5.9 and later.

A handler is able to annotate its functions with routes:

@HTTPHandler
struct MyHandler {

    @HTTPRoute("/ping")
    func ping() { }
    
    @HTTPRoute("/pong")
    func getPong(_ request: HTTPRequest) -> HTTPResponse {
        HTTPResponse(statusCode: .accepted)
    }
}

let server = HTTPServer(port: 80, handler: MyHandler())
try await server.start()

The macro synthesises conformance to HTTPHandler delegating handling to the first matching route. Expanding the example above to the following:

// expanded macro synthesis
func handleRequest(_ request: HTTPRequest) async throws -> HTTPResponse {
  if await HTTPRoute("/ping") ~= request {
    ping()
    return HTTPResponse(statusCode: .ok, headers: [:])
  }
  if await HTTPRoute("/pong") ~= request {
    return getPong(request)
  }
  throw HTTPUnhandledError()
}

@HTTPRoute annotations can specify specific properties of the returned HTTPResponse:

@HTTPRoute("/refresh", statusCode: .teapot, headers: [.eTag: "t3a"])
func refresh()

@JSONRoute annotations can be added to functions that accept Codable types. JSONDecoder decodes the body that is passed to the method, the returned object is encoded to the response body using JSONEncoder:

@JSONRoute("POST /account")
func createAccount(body: AccountRequest) -> AccountResponse

The original HTTPRequest can be optionally passed to the method:

@JSONRoute("POST /account")
func createAccount(request: HTTPRequest, body: AccountRequest) -> AccountResponse

JSONEncoder / JSONDecoder instances can be passed for specific JSON coding strategies:

@JSONRoute("GET /account", encoder: JSONEncoder())
func getAccount() -> AccountResponse

@swhitty swhitty merged commit 5981c9e into preview/macro Oct 29, 2023
14 checks passed
@swhitty swhitty deleted the initial-macro-implemenation branch October 29, 2023 03:20
@swhitty swhitty changed the title Handler Macro (@HTTPRoute / @JSONRoute) Preview HTTPHandler Macro (@HTTPRoute / @JSONRoute) Oct 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant