akane

Simple usage

let my_server = newServer("127.0.0.1", 8080)  # starts server at https://127.0.0.1:8080

my_sever.pages:
  "/":
    echo "Index page"
    await request.answer("Hello, world!")
  notfound:
    echo "oops :("
    await request.error("404 Page not found.")

Types

ServerRef = ref object
  port*: uint16
  address*: string
  server*: AsyncHttpServer

Consts

AnyHttpMethod = [HttpHead, HttpGet, HttpPost, HttpPut, HttpDelete, HttpTrace,
                 HttpOptions, HttpConnect, HttpPatch]
BaseHttpMethod = [HttpHead, HttpGet, HttpPost, HttpPut, HttpDelete]

Procs

proc newServer(address: string = "127.0.0.1"; port: uint16 = 5000): ServerRef {...}{.
    raises: [OSError, IOError], tags: [ReadDirEffect, WriteDirEffect].}

Creates a new ServerRef object.

Arguments:

  • address - server address, e.g. "127.0.0.1"
  • port - server port, e.g. 5000

Example

let server = newServer("127.0.0.1", 5000)
proc loadtemplate(name: string; json: JsonNode = %*{}): Future[string] {...}{.inline,
    raises: [Exception, ValueError], tags: [RootEffect].}

Loads HTML template from templates folder.

Arguments:

  • name - template's name, e.g. "index", "api", etc.
  • json - Json data, which replaces in the template.

Replaces:

  • @key -> value
  • if @key { ... } -> ... (if value is true)
  • if not @key { ... } -> ... (if value is false)
  • for i in 0..@key { ... } -> ........., etc
  • @key[0] -> key[0]

Example

let template = loadtemplate("index.html", %*{"a": 5})
proc parseQuery(request: Request): Future[JsonNode] {...}{.
    raises: [Exception, ValueError], tags: [RootEffect].}
Decodes query.
e.g.:
"a=5&b=10" -> {"a": "5", "b": "10"}

This also have debug output, if compiled in debug mode.

proc newCookie(server: ServerRef; key, value: string; domain = ""): HttpHeaders {...}{.
    inline, raises: [KeyError], tags: [].}

Creates a new cookies

Arguments:

  • key is a cookie key.
  • value is a new cookie value.
  • domain is a cookie doomain.
proc password2hash(password: string): Future[string] {...}{.inline,
    raises: [Exception, ValueError], tags: [RootEffect].}

Generates a sha1 from password.

Arguments:

  • password is an user password.

WARNING! It's works only with -d:tools.

proc validatePassword(password, hashpassword: string): Future[bool] {...}{.inline,
    raises: [Exception, ValueError], tags: [RootEffect].}

Validates the password and returns true, if the password is valid.

Arguments:

  • password is a got password from user input.
  • hashpassword is a response from password2hash proc

WARNING! It's works only with -d:tools.

Macros

macro pages(server: ServerRef; body: untyped): untyped

This macro provides convenient page adding.

body should be StmtList. page type can be:

  • equals
  • startswith
  • endswith
  • regex - match url via regex.
  • notfound - this page uses without URL argument.

When a new request to the server is received, variables are automatically created:

  • request - new Request.
  • url - matched URL.
    • equals - URL is request.url.path
    • startswith - URL is text after startswith.
    • endswith - URL is text before endswith.
    • regex - URL is matched text.
    • notfound - url param not created.
  • urlParams - query URL (in JSON).
  • decoded_url - URL always is request.url.path
  • cookies - StringTable of cookies.

Example:

let server = newServer()
server.pages:
  equals("/home"):
    echo url
    echo urlParams
    await request.answer("Home")
  # You can also not write `equals("/")`:
  "/helloworld":
    await request.answer("Hello, world")
macro send(request, message: untyped; http_code = Http200;
           headers: HttpHeaders = newHttpHeaders()): untyped

Responds from server with utf-8. Note: Content-length does not send automatically.

Translates to

request.respond(Http200, $message, headers)

Example

await request.send("hello!")
macro answer(request, message: untyped; http_code = Http200;
             headers: HttpHeaders = newHttpHeaders()): untyped

Responds from server with utf-8. Note: Content-length does not send automatically.

Translates to

request.respond(Http200, "<head><meta charset='utf-8'></head>" & message, headers)

Example

await request.answer("hello!")
macro error(request, message: untyped; http_code = Http404;
            headers: HttpHeaders = newHttpHeaders()): untyped

Responds from server with utf-8. Note: Content-length not automatically sends.

Translates to

request.respond(Http404, "<head><meta charset='utf-8'></head>" & message)

Example

await request.error("Oops! :(")
macro sendJson(request, message: untyped; http_code = Http200): untyped

Sends JsonNode with "Content-Type": "application/json" in headers. Note: Content-length does send automatically.

Translates to

request.respond(Http200, $message, newHttpHeaders([("Content-Type","application/json")]))

Example

await request.sendJson(%*{"response": "error", "msg": "oops :("})
macro sendPlaintext(request, message: untyped; http_code = Http200): untyped

Sends JsonNode with "Content-Type": "application/json" in headers. Note: Content-length does send automatically.

Translates to

request.respond(Http200, $message, newHttpHeaders([("Content-Type","plain/text")]))

Example

await request.sendPlaintext(%*{"response": "error", "msg": "oops :("})
macro start(server: ServerRef): untyped
Starts server.

Example

let server = newServer()
server.start()