Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/dom96/jester

A sinatra-like web framework for Nim.
https://github.com/dom96/jester

framework hacktoberfest http nim web

Last synced: 25 days ago
JSON representation

A sinatra-like web framework for Nim.

Awesome Lists containing this project

README

        

# 🃏 Jester 🃏

The sinatra-like web framework for Nim. Jester provides a DSL for quickly
creating web applications in Nim.

```nim
# example.nim
import htmlgen
import jester

routes:
get "/":
resp h1("Hello world")
```

Compile and run with:

```
cd tests/example
nim c -r example.nim
```

View at: [localhost:5000](http://localhost:5000)

Before deploying to production ensure you run your application behind a reverse proxy. This library is not yet hardened against HTTP security exploits so applications written in it should not be exposed to the public internet.

## Routes

```nim
routes:
get "/":
# do something here.
```

All routes must be inside a ``routes`` block.

Routes will be executed in the order that they are declared. So be careful when
halting.

The route path may contain a special pattern or just a static string. Special
patterns are almost identical to Sinatra's, the only real difference is the
use of ``@`` instead of the ``:``.

```nim
get "/hello/@name":
# This matches "/hello/fred" and "/hello/bob".
# In the route ``@"name"`` will be either "fred" or "bob".
# This can of course match any value which does not contain '/'.
resp "Hello " & @"name"
```

The patterns in Jester are currently a bit more limited, there is no
wildcard patterns.

You can use the '?' character to signify optional path parts.

```nim
get "/hello/@name?":
# This will match what the previous code example matches but will also match
# "/hello/".
if @"name" == "":
resp "No name received :("
else:
resp "Hello " & @"name"
```

In this case you might want to make the leading '/' optional too, you can do this
by changing the pattern to "/hello/?@name?". This is useful because Jester will
not match "/hello" if the leading '/' is not made optional.

### Regex

Regex can also be used as a route pattern. The subpattern captures will be
placed in ``request.matches`` when a route is matched. For example:

```nim
get re"^\/([0-9]{2})\.html$":
resp request.matches[0]
```

This will match URLs of the form ``/15.html``. In this case
``request.matches[0]`` will be ``15``.

## Conditions

Jester supports conditions, however they are limited to a simple ``cond`` template.

```nim
routes:
get "/@name":
cond @"name" == "daniel"
# ``cond`` will pass execution to the next matching route if @"name" is not
# "daniel".
resp "Correct, my name is daniel."

get "/@name":
# This will be the next route that is matched.
resp "No, that's not my name."
```

## Return values

Route bodies all have an implicit ``request`` object. This object is documented
in jester.nim and documentation can be generated by executing ``nim doc jester.nim``.

Returning a response from a route should be done using one of the following
functions:

* One of the ``resp`` functions.
* By setting ``body``, ``headers`` and/or ``status`` and calling ``return``.
* ``redirect`` function
* ``attachment`` function

There might be more. Take a look at the documentation of jester.nim for more info.

## Manual routing

It is possible not to use the ``routes`` macro and to do the routing yourself.

You can do this by writing your own ``match`` procedure. Take a look at
[example2](tests/example2.nim) for an example on how to do this.

## Static files

By default Jester looks for static files in ``./public``. This can be overriden
using the ``setStaticDir`` function. Files will be served like so:

./public/css/style.css ``->`` http://example.com/css/style.css

**Note**: Jester will only serve files, that are readable by ``others``. On
Unix/Linux you can ensure this with ``chmod o+r ./public/css/style.css``.

## Cookies

Cookies can be set using the ``setCookie`` function.

```nim
get "/":
# Set a cookie "test:value" and make it expire in 5 days.
setCookie("test", @"value", daysForward(5))
```

They can then be accessed using the ``request.cookies`` procedure which returns
a ``Table[string, string]``.

## Request object

The request object holds all the information about the current request.
You can access it from a route using the ``request`` variable. It is defined as:

```nim
Request* = ref object
params*: StringTableRef ## Parameters from the pattern, but also the
## query string.
matches*: array[MaxSubpatterns, string] ## Matches if this is a regex
## pattern.
body*: string ## Body of the request, only for POST.
## You're probably looking for ``formData``
## instead.
headers*: StringTableRef ## Headers received with the request.
## Retrieving these is case insensitive.
formData*: MultiData ## Form data; only present for
## multipart/form-data
port*: int
host*: string
appName*: string ## This is set by the user in ``run``, it is
## overriden by the "SCRIPT_NAME" scgi
## parameter.
pathInfo*: string ## This is ``.path`` without ``.appName``.
secure*: bool
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
settings*: Settings
```

## Examples

### Custom router

A custom router allows running your own initialization code and pass dynamic settings to Jester before starting the async loop.

```nim
import asyncdispatch, jester, os, strutils

router myrouter:
get "/":
resp "It's alive!"

proc main() =
let port = paramStr(1).parseInt().Port
let settings = newSettings(port=port)
var jester = initJester(myrouter, settings=settings)
jester.serve()

when isMainModule:
main()
```

### Github service hooks

The code for this is pretty similar to the code for Sinatra given here: http://help.github.com/post-receive-hooks/

```nim
import jester, json

routes:
post "/":
var push = parseJson(@"payload")
resp "I got some JSON: " & $push
```