Skip to content
Open
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
2 changes: 2 additions & 0 deletions changelog.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

- **Breaking change:** By default `redirect` now skips future handlers, including when used in a `before` route. To retain the old behavior, set the parameter `halt=false` (e.g. `redirect("/somewhere", halt=false)`)

- Fix for [#211](https://github.com/dom96/jester/issues/211) - custom routers now have the same error handling as normal routes.

## 0.4.3 - 12/08/2019

Minor release correcting a few packaging issues and includes some other
Expand Down
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