Metadata-Version: 1.1
Name: klar
Version: 0.0.4
Summary: a micro web framework
Home-page: https://github.com/zweifisch/klar
Author: Feng Zhou
Author-email: zf.pascal@gmail.com
License: MIT
Description: # 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:
        
        * request
        * 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')  # default is GET
        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(request, response):
        	print('%s not found' % request.path)
            response.body = "%s not found on this server" % request.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
        # special params: body, code, headers
        def jsonp(body, request):
            callback = request.query.get('callback')
            if callback:
                body = "%s(%s)" % (callback, json.dumps(body))
                return body, ("Content-Type", "application/javascript")
        
        @app.get('/resource') -> jsonp:
        	return {"key": "value"}
        ```
        
        more than one processors:
        
        ```python
        @app.get('/resource') -> (jsonp, etags):
        	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)
        ```
        
Keywords: micro web framework restful
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Web Environment
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.3
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
