mummyutils

Utility package for mummy multithreaded server


Need help? Read Nimble

mummy_utils

Unofficial utility package for mummy thread server. Various helper functions.

Change log

  • Version >= 0.2.0 defaults to case insensitive params. Revert to case sensitive by defining -d:caseSensitiveParams.
  • Version > 0.1.0 requires mummy version > 0.4.0 or higher.
  • Version == 0.8.0 supports mummy version > 0.3.6 or higher.

Examples

import std/[json, options]

import mummy, mummy/routers
import mummy_utils


proc indexParams(request: Request) =
  # Named parameter from route URL
  echo "projectID:  " & @"projectID"

  # URI query param passed with ?invoiceID=123
  echo "invoiceID:  " & @"invoiceID"

  # Grab params
  echo paramsPath(request, "projectId")
  echo paramsQuery(request, "projectId")
  echo paramsBody(request, "projectId")

  resp(Http200, %* {"message": "Hello, World!"})


proc indexRedirect(request: Request) =
  redirect("/project/123/info")
  # redirect(Http301, "/project/123/info")


proc indexHeaders(request: Request) =
  var headers: HttpHeaders
  if request.cookies("pass") == "1234567890":
    setHeader("xauth", "secret")
  else:
    resp(Http401, "Not authorized")

  setHeader("Content-Type", "text/html")
  resp(Http200, headers, "<h1>Hello, World!</h1>")


proc indexHead(request: Request) =
  resp Http200


proc indexPost(request: Request) =
  let urlParam = @"projectID"
  if urlParam == "":
    resp(Http400, "Missing projectID")

  let body = parseJson(request.body)

  resp(Http200, ContentType.Text, body["msg"].getStr())


proc indexFile(request: Request) =
  sendFile("filepath/" & @"filename")


proc indexMultipart(request: Request) =
  var file: string
  for entry in request.multipart:
    if entry.data.isSome and entry.name == "croppedImage":
      let (start, last) = entry.data.get
      file = request.body[start .. last]
      break

  # Do something with file
  resp Http204


var router: Router
router.get("/project/@projectID/info", indexParams)
router.get("/redirect", indexRedirect)
router.get("/headers", indexHeaders)
router.head("/headers", indexHead)
router.post("/headers", indexPost)
router.get("/file/@filename", indexFile)
router.post("/multipart", indexMultipart)

let server = newServer(router)
echo "Serving on http://localhost:8080"
server.serve(Port(8080))

Routes

Examples

var router: Router
router.get("/project/@projectID/info", indexCustom)
router.post("/project/@projectID/info", indexCustom)

router.post("/project/@projectID/info",
  proc(request: Request) =
    echo "projectID:  " & @"projectID"
    echo "invoiceID:  " & @"invoiceID"
    resp(Http200, "Hello, World!")
)

Request fields

Examples

Request* = object
  params*: StringTableRef       ## Parameters from the pattern, but also the
                                ## query string.
  body*: string                 ## Body of the request, only for POST.
  headers*: HttpHeaders         ## Headers received with the request.
                                ## Retrieving these is case insensitive.
  multipart*: seq[MultipartEntry] ## Form data; only present for
                                ## multipart/form-data
  host*: string                 ## Hostname.
  secure*: bool                 ## From X-Forwarded-Proto header.
  path*: string                 ## Path of request.
  query*: string                ## Query string of request.
  cookies*: StringTableRef      ## Cookies from the browser.
  ip*: string                   ## IP address of the requesting client.
  reqMeth*: HttpMethod          ## Request method, eg. HttpGet, HttpPost

echo request.body
echo request.headers["Content-Type"]
echo request.host
echo request.ip
echo request.path
echo request.query
echo request.reqMethod
echo request.secure
echo request.cookies("glid")
echo request.cookies.hasKey("glid")

Request fields

proc body*(request: Request): string =
proc host*(request: Request): string =
proc ip*(request: Request): string =
proc path*(request: Request): string =
proc query*(request: Request): string =
proc reqMethod*(request: Request): HttpMethod =
proc multipart*(request: Request): seq[MultipartEntry] =
proc secure*(request: Request): bool =

Headers

Examples

echo request.headers["Content-Type"]
echo request.headers["Content-Typexxx"] # returns empty string
var headers: HttpHeaders
setHeader("Content-Type", "text/plain")

Headers

proc hasKey*(headers: HttpHeaders, key: string): bool =
template setHeader*(field, value: string) =

Set header of response. Requires you to initialize the header first.

Cookies

Examples

echo request.cookies("glid")
echo request.cookies.hasKey("glid")
let c = request.cookies
echo c["glid"]

cookies*

proc cookies*(request: Request, cookie: string): string =
proc cookies*(request: Request): StringTableRef =

Get cookies of request.

setCookie*

template setCookie*(
    key, value: string,
    domain = "", path = "", expires = "";
    noName = false, secure = true, httpOnly = true,
    maxAge = none(int),
    sameSite = SameSite.Default
  ) =

Sets the cookie - will remove any other cookies with the same name.

setCookie*

template setCookie*(
    key, value: string,
    expires: DateTime | Time,
    domain = "", path = "",
    noName = false, secure = true, httpOnly = true,
    maxAge = none(int),
    sameSite = SameSite.Default
  ) =

Sets the cookie - will remove any other cookies with the same name.

addCookie*

template addCookie*(
    key, value: string,
    domain = "", path = "", expires = "";
    noName = false, secure = true, httpOnly = true,
    maxAge = none(int),
    sameSite = SameSite.Default
  ) =

Add cookie to response but requires the header to be available.

addCookie*

template addCookie*(
    key, value: string,
    expires: DateTime | Time,
    domain = "", path = "",
    noName = false, secure = true, httpOnly = true,
    maxAge = none(int),
    sameSite = SameSite.Default
  ) =

Add cookie to response but requires the header to be available.

Params

Examples

echo request.params("projectID")
echo request.params("invoiceID")

let p = request.params
echo p["projectID"]
echo p.hasKey("invoiceID")

params*

template params*(request: Request): StringTableRef =

Returns all params as a StringTableRef.

template params*(request: Request, s: string): string =

Get params. Is initialized on each call. Includes named route parameters. Returns the value on first match in this order:

  1. URI path
  2. URI query
  3. body data
template paramPath*(request: Request, s: string): string =

Get param from URI path.

template paramQuery*(request: Request, s: string): string =

Get param from URI query.

template paramBody*(request: Request, s: string): string =

Get param from body data (if Content-Type is application/x-www-form-urlencoded).

@*

echo @"projectID"
echo @"invoiceID"
template `@`*(s: string): untyped =

Get param. Includes named route parameters. Returns the value on first match in this order:

  1. URI path
  2. URI query
  3. body data

Responses

Examples

resp("Hello, World!")
resp(Http200, "Hello, World!")
resp(Http200, ContentType.Html, "Hello, World!")
resp(Http200, @{"Content-Type": "text/plain"}, "Hello, World!")
resp(%* {"message": "Hello, World!"})
resp(Http200, %* {"message": "Hello, World!"})
resp(Http200, ContentType.Json, %* {"message": "Hello, World!"})
redirect("/project/123/info")
redirect(Http301, "/project/123/info")
sendFile("images/logo.png")
var headers: HttpHeaders
setHeader("xauth", "1234567890")
setHeader("Content-Type", "text/html")
resp(Http200, headers, "Hello, World!")

# or

var headers: HttpHeaders
setHeader("xauth", "1234567890")
resp(Http200, "Hello, World!")

ContentType*

  ContentType* = enum
    Json = "application/json"
    Text = "text/plain"
    Html = "text/html; charset=utf-8"

resp*() - string

If the headers is declared, they will be used in the resp().

template resp*(body: string) =
template resp*(httpStatus: HttpCode) =
template resp*(httpStatus: HttpCode, body: string) =
template resp*(httpStatus: HttpCode, contentType: ContentType, body: string) =
template resp*(httpStatus: HttpCode = Http200, headers: HttpHeaders, body: string) =

resp*() - JsonNode

template resp*(body: JsonNode) =
template resp*(httpStatus: HttpCode, body: JsonNode) =
template resp*(httpStatus: HttpCode, contentType: ContentType, body: JsonNode) =

sendFile*() -

template sendFile*(path: string) =

redirect*

template redirect*(path: string) =
template redirect*(httpStatus: HttpCode, path: string) =

Converting existing routes from jester => mummy

mummy_utils was developed to ease the transition from jester to mummy. In mummy_utils you have access to many of the same sugar functions that jester provides.

Examples

Jester

routes:
  get "/project/@projectID/info":
    echo "projectID:  " & @"projectID"
    resp "Hello, World!"

Mummy #1

var router: Router
router.get("/project/@projectID/info",
  proc(request: Request) =
    echo "projectID:  " & @"projectID"
    resp "Hello, World!"
)

Mummy #2

var router: Router
router.get("/project/@projectID/info", proc(request: Request) =
  echo "projectID:  " & @"projectID"
  resp "Hello, World!"
)

Mummy #3

proc indexCustom(request: Request) =
  echo "projectID:  " & @"projectID"
  resp "Hello, World!"

var router: Router
router.get("/project/@projectID/info", indexCustom)

Author: ThomasTJdev

Licence: MIT

Project website

Docs