Skip to content

Routing

Routing is the core of web framework.

Static Routing

Registering handler hello by specifying path, HTTP methods and middlewares.

HttpGet is the default HTTP methods. If you have registered a handler with HttpGet, Prologue will automatically register HttpHead for this handler.

# handler
import prologue


proc hello*(ctx: Context) {.async.} =
  resp "<h1>Hello, Prologue!</h1>"


var app = newApp()
app.addRoute("/hello", hello)
# or
# app.get("/hello", hello)
app.run()

You can also use seq[HttpMethod] to register the same handler but supports multiple HTTP methods.

import prologue


# handler
proc hello*(ctx: Context) {.async.} =
  resp "<h1>Hello, Prologue!</h1>"

var app = newApp()
app.addRoute("/hello", hello, @[HttpGet, HttpPost])
app.run()

Parameters Routing

Prologue supports parameters route. You can use getPathParams to get named arguments.

Basic Example

import prologue


proc hello*(ctx: Context) {.async.} =
  resp "<h1>Hello, " & ctx.getPathParams("name", "Prologue") & "</h1>"

var app = newApp()
app.addRoute("/hello/{name}", hello, HttpGet)
app.run()

Wildcard

Wildcard will match only one URL section. For examples, /static/* only match /static/static.css, /static/etc and so on. You should use greedy($) character to match multiple URL sections.

import prologue


proc hello*(ctx: Context) {.async.} =
  resp "Hello, Prologue"

var app = newApp()
app.get("/static/*", hello)
app.get("/*/static", hello)
app.get("/static/templates/{path}/*", hello)
app.run()

Greedy

Greedy character($) will match all the remaining URL sections. But it can only used at the end of the URL. RouteError will be raised if it is used in the middle of the URL.

For /test/{param}$, /test/foo/bar/baz/ is matched. The path parameter is "foo/bar/baz". For /test/*$, /test/static/foo/bar/baz/ is matched.

import prologue


proc hello*(ctx: Context) {.async.} =
  resp "Hello, Prologue"

var app = newApp()
app.get("/test/{param}$", hello)
app.get("/test/static/*$", hello)
app.run()

Regex Routing

Prologue supports regex route.

import prologue


proc articles*(ctx: Context) {.async.} =
  resp $ctx.getPathParams("num", 1)

var app = newApp()
app.addRoute(re"/post(?P<num>[\d]+)", articles, HttpGet)
app.run()

Pattern Routing

import prologue

proc hello(ctx: Context) {.async.} =
  resp "Hello World!"

const urlPatterns = @[
  pattern("/hello", hello)
]

var app = newApp()

app.addRoute(urlPatterns, "")
app.run()

Group Routing

Prologue supports group route. You can add arbitrary levels of route.

import prologue


var
  app = newApp()
  base = newGroup(app, "/apiv2", @[])
  level1 = newGroup(app,"/level1", @[], base)
  level2 = newGroup(app, "/level2", @[], level1)
  level3 = newGroup(app, "/level3", @[], level2)


proc hello(ctx: Context) {.async.} =
  resp "Hello"

proc hi(ctx: Context) {.async.} =
  resp "Hi"

proc home(ctx: Context) {.async.} =
  resp "Home"

# /apiv2/hello
base.get("/hello", hello)
base.get("/hi", hi)
base.post("/home", home)


# /apiv2/level1/hello
level1.get("/hello", hello)
level1.get("/hi", hi)
level1.post("/home", home)

# /apiv2/level1/level2/hello
level2.get("/hello", hello)
level2.get("/hi", hi)
level2.post("/home", home)

# /apiv2/level1/level2/level3/hello
level3.get("/hello", hello)
level3.get("/hi", hi)
level3.post("/home", home)

app.run()

std/with provides a more neat routing fashion:

import prologue
import std/with


var 
  app = newApp()
  base = newGroup(app, "/apiv2", @[])
  level1 = newGroup(app,"/level1", @[], base)
  level2 = newGroup(app, "/level2", @[], level1)
  level3 = newGroup(app, "/level3", @[], level2)


proc hello(ctx: Context) {.async.} =
  resp "Hello"

proc hi(ctx: Context) {.async.} =
  resp "Hi"

proc home(ctx: Context) {.async.} =
  resp "Home"


with base:
  get("/hello", hello)
  get("/hi", hi)
  post("/home", home)

# /apiv2/level1/hello
with level1:
  get("/hello", hello)
  get("/hi", hi)
  post("/home", home)

# /apiv2/level1/level2/hello
with level2:
  get("/hello", hello)
  get("/hi", hi)
  post("/home", home)

# /apiv2/level1/level2/level3/hello
with level3:
  get("/hello", hello)
  get("/hi", hi)
  post("/home", home)

app.run()

pattern routing also supports grouping.

import prologue


var
  app = newApp()
  base = newGroup(app, "/apiv2", @[])
  level1 = newGroup(app,"/level1", @[], base)
  level2 = newGroup(app, "/level2", @[], level1)


proc hello(ctx: Context) {.async.} =
  resp "Hello"

proc hi(ctx: Context) {.async.} =
  resp "Hi"

proc home(ctx: Context) {.async.} =
  resp "Home"


let
  urlpattern1 = @[pattern("/hello", hello), pattern("/hi", hi)]
  urlpattern2 = @[pattern("/home", home)]
  tab = {level1: urlpattern1, level2: urlpattern2}

app.addGroup(tab)
app.run()

Tips

You could compile the main program with -d:logueRouteLoose to enable loose route matching. Text and wildcard or text and parameters are considered different. For example /blog/tag/{slug} and /blog/{year}/{id} are not considered as the duplicated routes. If you define /blog/tag/{slug} first, then it will be matched first. Order matters. But /blog/*/{slug} and /blog/{year}/{id} are still duplicated.