Skip to content

Commit

Permalink
Fix dom96#211 - custom routers now get the same default error handlin…
Browse files Browse the repository at this point in the history
…g as normal routers
  • Loading branch information
iffy committed Sep 18, 2020
1 parent 8f89f0c commit 3a4d816
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 9 deletions.
46 changes: 37 additions & 9 deletions jester.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ type
request: Request, error: RouteError
): Future[ResponseData] {.gcsafe, closure.}

MatchPair* = tuple
matcher: MatchProc
errorHandler: ErrorProc

MatchPairSync* = tuple
matcher: MatchProcSync
errorHandler: ErrorProc

Jester* = object
when not useHttpBeast:
httpServer*: AsyncHttpServer
Expand Down Expand Up @@ -449,18 +457,20 @@ proc initJester*(
result.errorHandlers = @[]

proc initJester*(
matcher: MatchProc,
pair: MatchPair,
settings: Settings = newSettings()
): Jester =
result = initJester(settings)
result.register(matcher)
result.register(pair.matcher)
result.register(pair.errorHandler)

proc initJester*(
matcher: MatchProcSync, # TODO: Annoying nim bug: `MatchProc | MatchProcSync` doesn't work.
pair: MatchPairSync, # TODO: Annoying nim bug: `MatchPair | MatchPairSync` doesn't work.
settings: Settings = newSettings()
): Jester =
result = initJester(settings)
result.register(matcher)
result.register(pair.matcher)
result.register(pair.errorHandler)

proc serve*(
self: var Jester
Expand Down Expand Up @@ -1288,7 +1298,7 @@ proc routesEx(name: string, body: NimNode): NimNode =
`afterRoutes`
)

let matchIdent = newIdentNode(name)
let matchIdent = newIdentNode(name & "Matcher")
let reqIdent = newIdentNode("request")
let needsAsync = needsAsync(body)
case needsAsync
Expand Down Expand Up @@ -1348,6 +1358,26 @@ proc routesEx(name: string, body: NimNode): NimNode =
errorHandlerProc[6][0][1][^1][2][1][0] = stmts
result.add(errorHandlerProc)

# Pair the matcher and error matcher
let pairIdent = newIdentNode(name)
let matchProcVarIdent = newIdentNode(name & "MatchProc")
let errorProcVarIdent = newIdentNode(name & "ErrorProc")
if needsAsync in {ImplicitTrue, ExplicitTrue}:
# TODO: I don't understand why I have to assign these procs to intermediate
# variables in order to get them into the tuple. It would be nice if it could
# just be:
# let `pairIdent`: MatchPair = (`matchIdent`, `errorHandlerIdent`)
result.add quote do:
let `matchProcVarIdent`: MatchProc = `matchIdent`
let `errorProcVarIdent`: ErrorProc = `errorHandlerIdent`
let `pairIdent`: MatchPair = (`matchProcVarIdent`, `errorProcVarIdent`)
else:
result.add quote do:
let `matchProcVarIdent`: MatchProcSync = `matchIdent`
let `errorProcVarIdent`: ErrorProc = `errorHandlerIdent`
let `pairIdent`: MatchPairSync = (`matchProcVarIdent`, `errorProcVarIdent`)


# TODO: Replace `body`, `headers`, `code` in routes with `result[i]` to
# get these shortcuts back without sacrificing usability.
# TODO2: Make sure you replace what `guessAction` used to do for this.
Expand All @@ -1358,13 +1388,11 @@ proc routesEx(name: string, body: NimNode): NimNode =
macro routes*(body: untyped) =
result = routesEx("match", body)
let jesIdent = genSym(nskVar, "jes")
let matchIdent = newIdentNode("match")
let errorHandlerIdent = newIdentNode("matchErrorHandler")
let pairIdent = newIdentNode("match")
let settingsIdent = newIdentNode("settings")
result.add(
quote do:
var `jesIdent` = initJester(`matchIdent`, `settingsIdent`)
`jesIdent`.register(`errorHandlerIdent`)
var `jesIdent` = initJester(`pairIdent`, `settingsIdent`)
)
result.add(
quote do:
Expand Down
20 changes: 20 additions & 0 deletions tests/customRouter.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import jester

router myrouter:
get "/":
resp "Hello world"

get "/raise":
raise newException(Exception, "Foobar")

error Exception:
resp Http500, "Something bad happened: " & exception.msg

when isMainModule:
let s = newSettings(
Port(5454),
bindAddr="127.0.0.1",
)
var jest = initJester(myrouter, s)
# jest.register(myrouterErrorHandler)
jest.serve()
14 changes: 14 additions & 0 deletions tests/tester.nim
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,26 @@ proc issue150(useStdLib: bool) =
check resp.code == Http500
check (waitFor resp.body).startsWith("Something bad happened")

proc customRouterTest(useStdLib: bool) =
waitFor startServer("customRouter.nim", useStdLib)
var client = newAsyncHttpClient(maxRedirects = 0)

suite "customRouter useStdLib=" & $useStdLib:
test "error handler":
let resp = waitFor client.get(address & "/raise")
check resp.code == Http500
let body = (waitFor resp.body)
checkpoint body
check body.startsWith("Something bad happened: Foobar")

when isMainModule:
try:
allTest(useStdLib=false) # Test HttpBeast.
allTest(useStdLib=true) # Test asynchttpserver.
issue150(useStdLib=false)
issue150(useStdLib=true)
customRouterTest(useStdLib=false)
customRouterTest(useStdLib=true)

# Verify that Nim in Action Tweeter still compiles.
test "Nim in Action - Tweeter":
Expand Down

0 comments on commit 3a4d816

Please sign in to comment.