Skip to main content
# klar

a micro web framework built for fun

* argument annotation
* jsonschema intergration

```py
from klar import App

app = App()

@app.get('/hello/<name>')
def hello(name: str, times: int = 1):
return "hello " * times + name
```

run it using [wsgi-supervisor](https://github.com/zweifisch/wsgi-supervisor)

```sh
wsgi-supervisor app:app
```

```sh
$ curl 'localhost:3000/hello/klar?times=2'
hello hello klar
```

## custom types using jsonschema

```python
product = {
"type": "object"
"properties": {
"name": {
"type": "string"
},
"price": {
"type": "number"
},
},
"additionalProperties": False,
}

@app.post('/product')
def create(body: product, db):
db.products.insert(body)
return {"ok": True}
```

schemas can and should be imported from json or yaml files

```
|--app.py
|--schemas.json
```

product in schema.json

```
{
product: {...}
}
```

```python
from schemas import product

@app.post('/product')
def create(body: product):
pass
```

## dependency injection

provide a custom dependency using decorator

```python
@app.provide('db')
def get_db_connection():
conn = SomeDB(url="localhost:3349")
return conn

import redis
app.provide('cache', (redis.Redis, {'host': 'localhost'}))
```

using `db` and `cache` in request handler

```python
@get('/article/<article_id>')
def get_article(article_id:int, db, cache):
pass
```

predefined components:

* req
* session
* cookie
* router

## rest

```python
from resource import product, catalog

app = App()

app.resources(product, catalog, prefix="/v1")

if __name__ == '__main__':
app.run()
```

in product

```python
from schema import product

# curl -X POST $host/v1/product -d @body
def create(body: product, db):
return db.products.insert(body)

# curl $host/v1/product/$id
def show(product_id: str):
item = db.products.find_one({_id: product_id})
return item if item else 404

# curl $host/v1/product?shift=10&limit=10
def query(shift: int, limit: int, db):
return db.products.find().skip(shift).limit(shift)

# curl -X PATCH $host/v1/product/$id -d @body
def modify(body: product, product_id: str):
return db.products.update({_id: product_id}, {'$set': body})

# curl -X PUT $host/v1/product/$id -d @body
def replace(body: product, product_id: str):
return db.products.update({_id: product_id}, body)

# curl -X DELETE $host/v1/product/$id
def destroy(product_id: str):
return db.products.delete({_id: product_id})
```

### custom method

```python
from klar import method

@method('patch')
def like(product_id):
return db.products.update({_id: product_id}, {'$inc': {'likes': 1}})

# curl -X PATCH $host/v1/product/$id/like
```

## events

listening for an event

```python
@on(404)
def not_found(req, res):
print('%s not found' % req.path)
res.body = "%s not found on this server" % req.path
```

### custom events

```python
@on('user-login')
def onlogin(userid, db):
print('user: %s logged in' % userid)
db.users.update({_id:userid}, {'$inc': {'logincount': 1}})
```

emit an event

```python
def login(emitter):
emitter.emit('user-login', userid=id)
```

## post processing

```python
def jsonp(req, res):
callback = req.query.get('callback')
if callback:
res.body = "%s(%s)" % (callback, json.dumps(body))
res.headers["Content-Type"] = "application/javascript"

@app.get('/resource') -> jsonp:
return {"key": "value"}
```

more than one processors:

```python
@app.get('/resource') -> (jsonp, etag):
return {"key": "value"}
```

## template rendering

```
|--app.py
|--templates
|--home.html
```

```python
import templates.home

@app.get('/') -> templates.home:
return {"key": "value"}
```

`templates.home` accecpts an optional dict as argument
it's basically equivalent to this:

```python
@app.get('/'):
return templates.home({"key": "value"})
```

### mustache

depends on pystache, `pip install pystache`

use `.mustache` as extension

```
|--templates
|--home.mustache
```

```python
import templates.home
```

## session

session depends on `cache`, but klar does't has it builtin

to use redis as session backend:

```python
import redis

@app.provide('cache')
def cache():
return redis.Redis(host='localhost', port=6379, db=0)
```

or

```python
app.privide('cache', (redis.Redis, {'host': 'localhost'}))
```

### use session

```python
@app.post('/login')
def login(body, session):
# check body.username and body.password
if founduser:
session.set('userid', userid)

@app.post('/login')
def logout(session):
session.destroy()

@app.get('/admin')
def admin(session):
if session.get('userid'):
pass
```

## cookies

```python
cookies.get(key, default)
cookies.set(key, value)
cookies.delete(key)

cookies.set(key, value, httponly=True)
cookies.set_for_30_days(key, value)
```

## serving static files

should only be used in development enviroment

```
app.static('/public/')
```

```
app.static('/public/', 'path/to/public/dir')
```

## config

config file path will be read from enviroment variable `$CONFIG`

if it's empty config.py will be loaded

config.py

```python
mongo = {
"host": "127.0.0.1"
"port": 27017
}
```

```python
from pymongo import MongoClient

@app.provide('db')
def db(config):
return MongoClient(**config.mongo)
```

## reversed routing

```python
@app.get('user/<id>')
def user(id:str):
pass
```

get a link to previous handler

```
def another_handler(router):
href = router.path_for('user', id=3221)
```

## custom json encoder

```python
from bson.objectid import ObjectId

@app.json_encode(ObjectId)
def encode_objectid(obj):
return str(obj)
```

by default `Iterable` is converted to `list`

Metadata

Release files for klar 0.0.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for klar 0.0.6
File Size Uploaded
klar-0.0.6.tar.gz 12.7 kB Details

Release files / klar-0.0.6.tar.gz

Download URL klar-0.0.6.tar.gz
Size 12.7 kB
Tags Source
SHA-256 checksum
How to use checksums
aed1c2352f3e43db5ba999ad73fb5b272a7a5b4128469eb7820204996b8d6c99
BLAKE2b-256 checksum
How to use checksums
763548f95e0cf423e2eb6cd57cfb32a024f1b1d97bf642a3c98691d6c78b8d35
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release history Release notifications | RSS feed

This release

0.0.6 This release

1 release file

0.0.5

1 release file

0.0.4

1 release file

0.0.3

1 release file

0.0.2

1 release file

0.0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page