https://github.com/zweifisch/klar
a micro web framework built for fun
https://github.com/zweifisch/klar
Last synced: 4 months ago
JSON representation
a micro web framework built for fun
- Host: GitHub
- URL: https://github.com/zweifisch/klar
- Owner: zweifisch
- License: mit
- Created: 2014-02-17T13:28:58.000Z (about 11 years ago)
- Default Branch: master
- Last Pushed: 2024-04-11T09:02:42.000Z (about 1 year ago)
- Last Synced: 2025-01-02T03:07:52.983Z (5 months ago)
- Language: Python
- Size: 277 KB
- Stars: 2
- Watchers: 3
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# klar
a micro web framework built for fun
* argument annotation
* jsonschema intergration```py
from klar import Appapp = App()
@app.get('/hello/')
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 connimport redis
app.provide('cache', (redis.Redis, {'host': 'localhost'}))
```using `db` and `cache` in request handler
```python
@get('/article/')
def get_article(article_id:int, db, cache):
pass
```predefined components:
* req
* session
* cookie
* router## rest
```python
from resource import product, catalogapp = 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/')
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`