# Introduction

Make sure you are using `Python 3.6+` because Vibora takes advantage of some new Python features.

1. Install Vibora: `pip install vibora[fast]`

> It's highly recommended to install Vibora inside a virtualenv.
>
> In case you have trouble with Vibora dependencies: `pip install vibora` to install it without the extra libraries.

1. Create a file called `anything.py` with the following code:

```python
from vibora import Vibora, JsonResponse

app = Vibora()


@app.route('/')
async def home():
    return JsonResponse({'hello': 'world'})

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8000)
```

1. Run the server: `python3 anything.py`
2. Open your browser at `http://127.0.0.1:8000`

## Creating a project

The previous example was just to show off how easy is it to spin up a server.

The recommended way to start a new project is by letting Vibora do it for you. Vibora is also a command-line tool, try it out: `vibora new project_name`


# Routing

## Routing

Routing is the core of any web framework because it allows the user to map URL endpoints to functions.

```python
@app.route("/home", methods=['GET'])
async def home():
    return Response(b'123')
```

> In this example you are mapping every HTTP request with a `GET` method and a path equals to `/home` to `async def home()`.

## Request Parameters

Often parts of an URL have a special meaning, for example, specifying which product should be displayed.

```python
@app.route('/product/<product_id>')
async def show_product(product_id: int):
    return Response(f'Chosen product: {product_id}'.encode())
```

Not usually you'll need something more sophisticated. Vibora allows regular expressions as route patterns.

```python
import re

@app.route(re.compile('/product/(?P<product_id>[0-9]+)'))
async def show_product(product_id: int):
    return Response(f'Chosen product: {product_id}'.encode())
```

## Virtual Hosts

Maybe you have different domains and you want to host them all with a single Vibora application. So `http://docs.vibora.io/` and `http://vibora.io/` would hit the same application but return different responses based on the `HTTP host header`. Vibora makes it very easy thanks to the `hosts` attribute.

```python
@app.route('/', hosts=['docs.vibora.io'])
async def docs():
    return Response(b'Docs')

@app.route('/', hosts=['vibora.io'])
async def home():
    return Response(b'Home')
```

To avoid repeating the `hosts` attribute for every route, you can group routes using a Blueprint.

```python
from vibora.blueprints import Blueprint
from vibora.responses import Response


docs = Blueprint(hosts=['docs.vibora.io'])
main = Blueprint(hosts=['vibora.io'])


@docs.route('/')
async def docs():
    return Response(b'docs')


@main.route('/')
async def home():
    return Response(b'main')
```

## Router Strategies

A common source of headaches in URL routing are ending slashes.

Let's take the path `/home` and `/home/` for example.

In a web environment these are two completely different paths, it's up to the server to interpret those as the same or not.

Vibora has three different strategies to deal with this problem:

1. **Strict**. Does nothing. If you map your endpoints ending with

   slashes then if you try to access `/home` instead of `/home/`

   you'll get a 404 response.
2. **Redirect (Default)**. If you map your route as `/home` then

   Vibora will return a 302 response if someone tries to access `/home/`

   and vice-versa.
3. **Clone**. This one is similar to redirect but instead of a 302 it'll

   return the same response for both routes.

Configuration example:

```python
from vibora import Vibora
from vibora.router import RouterStrategy

app = Vibora(router_strategy=RouterStrategy.STRICT)
```

## Caching

Caching can be a tremendous ally when handling performance issues. Imagine an API that does a read-only query being hit by 10k requests/sec, this means that you are stressing your database at 10k queries/sec.

If you start caching the response for at least one second you drop from 10k queries/sec to 1 query per second. That's a huge improvement with almost no effort.

Vibora has some internal optimizations to speed-up cached APIs so instead of handling it all by ourselves, you should use the `CacheEngine`.

```python
from vibora import Vibora, Response, Request
from vibora.cache import CacheEngine

app = Vibora()


class YourCacheEngine(CacheEngine):
    async def get(self, request: Request):
        return self.cache.get(request.url)

    async def store(self, request: Request, response):
        self.cache[request.url] = response


@app.route('/', cache=YourCacheEngine(skip_hooks=True))
def home():
    return Response(b'Hello World')
```

> Notice the "skip\_hooks" parameter which makes cached responses to skip any listeners/hooks. Sometimes this is useful, often not, use wisely.

## Static Files

Vibora is fast enough to host static files and it tries hard to implement the same features as some battle proven solutions like Nginx.

By default Vibora will seek for a directory called "static" in the same parent directory related to the file that created Vibora app instance.

You can configure the `StaticHandler` as bellow:

> All parameters are optional.

```python
from vibora.static import StaticHandler

app = Vibora(
    static=StaticHandler(
        paths=['/your_static_dir', '/second_static_dir'],
        host='static.vibora.io',
        url_prefix='/static',
        max_cache_size=1 * 1024 * 1024
    )
)
```

> **Host** parameter can be used to only serve static files when the Host header matches this specific host.
>
> **max\_cache\_size** specifies the amount of memory that Vibora may invest into optimizations.


# Components

## Components

Every app has some hot objects that should be available almost everywhere. Maybe they are database instances, maybe request objects. Vibora call these objects `components`

For now you should pay close attention to the `Request` component:

This is the most important component and will be everywhere in your app. It holds all information related to the current request and also some useful references like the current application and route.

You can ask for components in your route by using type hints:

```python
from vibora import Vibora, Request, Response

app = Vibora()

@app.route('/')
async def home(request: Request):
    print(request.headers)
    return Response(b'123')
```

The request object has a special method that allows you to ask for more components as you go.

```python
from vibora import Vibora, Request, Response
from vibora import Route

app = Vibora()

@app.route('/')
async def home(request: Request):
    current_route = request.get_component(Route)
    return Response(current_route.pattern.encode())
```

> By now you should have noticed that Vibora is smart enough to know which components do you want in your routes so your routes may not receive any parameters at all or ask as many components do you wish.

## Adding custom components

Vibora was designed to avoid global magic (unlike Flask for example) because it makes testing harder and more prone to errors specially in async environments.

To help with this, Vibora provides an API where you can register objects to later use.

This means they are correctly encapsulated into a single app object, allowing many apps instances to work concurrently, encouraging the use of type hints which brings many benefits in the long-term and also make your routes much easier to test.

```python
from vibora import Vibora, Request, Response
from vibora import Route

# Config will be a new component.
class Config:
    def __init__(self):
        self.name = 'Vibora Component'

app = Vibora()

# Registering the config instance.
app.add_component(Config())

@app.route('/')
async def home(request: Request, config: Config):
    """
    Notice that if you specify a parameter of type "Config"
    Vibora will automatically provide the config instance registered previously.
    Instead of adding global variables you can now register new components,
    that are easily testable and accessible.
    """
    # You could also ask for the Config component at runtime.
    current_config = request.get_component(Config)
    assert current_config is config
    return Response(config.name)
```


# Request Component

## Request Component

The request component holds all the information related to the current request. Json, Forms, Files everything can be accessed through it.

## Receiving JSON

```python
from vibora import Vibora, Request
from vibora.responses import JsonResponse

app = Vibora()

@app.route('/')
async def home(request: Request):
    values = await request.json()
    print(values)
    return JsonResponse(values)

app.run()
```

Note that `request.json()` is actually a coroutine that needs to be **awaited**, this design prevents the entire JSON being uploaded in-memory before the route requires it.

## Uploaded Files

Uploaded files by multipart forms can be accessed by field name in `request.form` or through the `request.files` list. Both methods are co-routines that will consume the `request.stream` and store the file in-disk if it's too big to keep in-memory.

You can control the memory/disk usage of uploaded files by calling `request.load_form(threshold=1 * 1024 * 1024)` explicitly, in this case files bigger than 1mb will be flushed to disk.

> Please be aware that the form threshold does not passthrough the max\_body\_size limit so you'll still need to configure your route properly.

Instead of pre-parsing the entire form you could call `request.stream_form()` and deal with every uploaded field as it arrives by the network. This is good when you don't want files hitting the disk and in some scenarios allows you to waste less memory by doing way more coding yourself.

```python
import uuid
from vibora import Vibora, Request
from vibora.responses import JsonResponse

app = Vibora()

@app.route('/', methods=['POST'])
async def home(request: Request):
    uploaded_files = []
    for file in (await request.files):
        file.save('/tmp/' + str(uuid.uuid4()))
        print(f'Received uploaded file: {file.filename}')
        uploaded_files.append(file.filename)
    return JsonResponse(uploaded_files)
```

## Querystring

```python
from vibora import Vibora, Response, Request

app = Vibora()

@app.route('/')
async def home(request: Request):
    print(request.args)
    return Response(f'Name: {request.args['name']}'.encode())
```

> A request to <http://{address}/?name=vibora> would return 'Name: vibora'

## Raw Stream

Sometimes you need a low-level access to the HTTP request body, `request.stream` method provides an easy way to consume the stream by ourself.

```python
from vibora import Vibora, Request, Response

app = Vibora()

@app.route('/', methods=['POST'])
async def home(request: Request):
    content = await request.stream.read()
    return Response(content)
```

## URLs

Ideally you shouldn't need to deal with the URL directly but sometimes that's the only way. The request object carries two properties that can help you:

`request.url`: Raw URL

`request.parsed_url`: A parsed URL where you can access the path, host and all URL attributes easily. The URL is parsed by a fast Cython parser so there is no need to you re-invent the wheel.

```python
from vibora import Vibora, Request
from vibora.responses import JsonResponse

app = Vibora()

@app.route('/')
async def home(request: Request):
    return JsonResponse(
        {'url': request.url, 'parsed_url': request.parsed_url}
    )
```


# Responses

## Responses

Each route must return a Response object, the protocol will use these objects to encode the HTTP response and send through the socket.

There are many different response types but they all inherit from the base Response class.

Bellow there are the most important ones:

## JSON Response

Automatically dumps Python objects and adds the correct headers to match the JSON format.

```python
from vibora import Vibora, JsonResponse

app = Vibora()

@app.route('/')
async def home():
    return JsonResponse({'hello': 'world'})
```

## Streaming Response

Whenever you don't have the response already completely ready, be it because you don't want to waste memory by buffering, be it because you want the client to start receiving the response as soon as possible, a StreamingResponse will be more appropriate.

**A StreamingResponse receives a coroutine that yield bytes.**

Differently from simple responses, streaming ones have more timeout options because they are often long running tasks. Usually a route timeout works until the client consumes the entire response but with streaming responses this is not true. After the route return a StreamingResponse two new timeouts options take its place.

> **complete\_timeout: int**: How many seconds the client have to consume the **entire** response. So if you set it to 30 seconds the client will have 30 seconds to consume the entire response, in case not, the connection will be closed abruptly to avoid DOS attacks. You may set it to zero and completely disable this timeout, when chunk\_timeout is properly configured this is a reasonable choice.
>
> **chunk\_timeout: int**: How many seconds the client have to consume each response chunk. Lets say your function produces 30 bytes per yield and the chunk\_timeout is 10 seconds. The client will have 10 seconds to consume the 30 bytes, in case not, the connection will be closed abruptly to avoid DOS attacks.

```python
import asyncio
from vibora import Vibora, StreamingResponse

app = Vibora()

@app.route('/')
async def home():
    async def stream_builder():
        for x in range(0, 5):
            yield str(x).encode()
            await asyncio.sleep(1)

    return StreamingResponse(
           stream_builder, chunk_timeout=10, complete_timeout=30
    )
```

## Response

A raw Response object would fit whenever you need a more customized response.

```python
from vibora import Vibora, Response

app = Vibora()

@app.route('/')
async def home():
    return Response(b'Hello World', headers={'content-type': 'html'})
```


# Data Validation

## Data Validation

Data validation is a common task in any web related activity. Vibora has a module called `schemas` to build, guess what, schemas, and validate your data against them. They are very similar to `marshmallow` and other famous libraries except they have some speedups written in Cython for amazing performance.

Schemas are also asynchronous meaning that you can do database checkups and everything in a single place, something that cannot be done in other libraries which forces you to split your validation logic between different places.

## Usage Example

### Declaring your schema

```python
from vibora.schemas import Schema, fields
from vibora.schemas.exceptions import ValidationError
from vibora.schemas.validators import Length, Email
from vibora.context import get_component
from .database import Database


class AddUserSchema(Schema):

    @staticmethod
    async def unique_email(email: str):
        # You can get any existent component by using "vibora.context"
        database = get_component(Database)
        if await database.exists_user(email):
            raise ValidationError(
                'There is already a registered user with this e-mail'
            )

    # Custom validations can be done by passing a list of functions
    # to the validators keyword param.
    email: str = fields.Email(pattern='.*@vibora.io',
            validators=[unique_email]
    )

    # There are many builtin validation helpers as Length().
    password: str = fields.String(validators=[Length(min=6, max=20)])

    # In case you just want to enforce the type of a given field,
    # a type hint is enough.
    name: str
```

### Using your schema

```python
from vibora import Request, Blueprint, JsonResponse
from .schemas import AddUserSchema
from .database import Database

users_api = Blueprint()

@users_api.route('/add')
async def add_user(request: Request, database: Database):

    # In case the schema is invalid an exception will be raised
    # and catched by an exception handler, this means you don't need to
    # repeat yourself about handling errors. But in case you want to
    # customize the error message feel free to catch the exception
    # and handle it your way. "from_request" method is just syntatic sugar
    # to avoid calling request.json() yourself.
    schema = await AddUserSchema.from_request(request)

    # By now our data is already valid and clean,
    # so lets add our user to the database.
    database.add_user(schema)

    return JsonResponse({'msg': 'User added successfully'})
```

> Type hints must always be provided for each field. In case the field is always required and do not have any custom validation the type hint alone will be enough to Vibora build your schema.


# Fields

## Fields

Vibora has a special class called "Field" to represent each field of a schema. You can build any kind of validation rules using this class but to avoid repeat yourself there a few builtin ones. There are a few must-know attributes of this class:

1\) **required** -> By default all declared fields in a schema are required which means they must be present in the validation values. If you have optional fields you must explicitely declare this as `Field(required=False)`

2\) **load\_from** -> Sometimes is useful to deal with friendly names inside a schema but to ofuscate them outside outside your app, by using the `load_from` parameter you can specify where to load this field from or even load two different fields from the same key.

3\) **default** -> A default value in case the key is missing or the value is null.

4\) **validators** -> A list of functions to validate the current value against. This functions can be async or sync and receive one up to two parameters. In case it receives a single parameter then Vibora will pass only the current value to it. In case it receive two parameters the context of the schema will be also provided. The exception `ValidationError` must be raised to notify the schema that this field is invalid, returning values are ignored.

## StringField

Validates if the given value is a valid string.

```python
import uuid
from vibora.schemas import Schema, fields
from vibora.schemas.validators import Length

class NewUserSchema(Schema):

    name: str = fields.String(
        required=False,
        validators=[Length(min=3, max=30)],
        default=lambda: str(uuid.uuid4()),
        strict=False
    )
```

> There is a special attribute called `strict` to allow this field to cast integers and similar types to a string instead of raising an error.


# Events

Hooks are functions that are called after an event.

Let's suppose you want to add a header to every response in your app. Instead of manually editing every single route in your app you can just register a listener to the event "BeforeResponse" and inject the desired headers.

Below is a fully working example:

```python
from vibora import Vibora, Response
from vibora.hooks import Events

app = Vibora()

@app.route('/')
async def home():
    return Response(b'Hello World')

@app.handle(Events.BEFORE_RESPONSE)
async def before_response(response: Response):
    response.headers['x-my-custom-header'] = 'Hello :)'

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

Hooks can halt a request and prevent a route from being called, completely modify the response, handle app start/stop functionalities, initialize components and do all kind of stuff.

> The golden rule is: If you don't want to modify the request flow (like halting requests) you don't want to return anything in your function. Of course that depends on which event you are listening to.


# Testing

Testing is the most important part of any project with considerably size and yet of one of the most ignored steps.

Vibora has a builtin and fully featured async HTTP client and a simple test framework to make it easier for you as in the example bellow:

```python
from vibora import Vibora, Response
from vibora.tests import TestSuite

app = Vibora()


@app.route('/')
async def home():
    return Response(b'Hello World')


class HomeTestCase(TestSuite):
    def setUp(self):
        self.client = app.test_client()

    async def test_home(self):
        response = await self.client.get('/')
        self.assertEqual(response.content, b'Hello World')
```


# Advanced Tips

Under construction


# Template Engine

Although server-side rendering is not main-stream nowadays, Vibora has its own template engine. The idea was to build something like Jinja2 but with async users as first class citizens. Jinja2 is already heavily optimized but we tried to beat it in benchmarks.

Jinja2 also prevents you to pass parameters to functions and a few other restrictions which are often a good idea but don't comply with Vibora philosophy of not getting into your way.

The syntax is pretty similar to Jinja2, templates are often compatible.

The render process is async which means you can pass coroutines to your templates and call them as regular functions, Vibora will do the magic.

VTE has hot-reloading so we can swap templates at run-time. This is enabled by default in debug mode so you have a fast iteration cycle while building your app.

Although VTE **do not aim to be sandboxed** it tries hard to prevent the templates from leaking access to outside context.


# Syntax

VTE syntax is basically split between two things: Tags and Expressions.

```markup
<html>
    <head>
        <title> {{ title }} </title>
    </head>
    <body>
        <ul>
            {% for user in users %}
                <li> {{ user.name}} </li>
            {% endfor %}
        </ul>
    </body>
</html>
```

1\) Expressions are delimited by "{ { variable\_name } }" and they are used to print data.

2\) Tags are delimited by "{ % tag\_name % }" and they are used to express intents like loops, conditionals, etc.

> There are many default tags and you can create your own too by adding an extension, you can also customize the markers so instead of "{%" you could use "#\[" or whatever do you think it's best.


# Extending

WIP...


# Performance

WIP...


# Logging

Vibora has a simple logging mechanism to avoid locking you into our library of choice.

You must provide a function that receives two parameters: a msg and a logging level (that matches logging standard library for usability sake).

That's all.

It's up to you to choose what to do with logging messages.

```python
import logging
from vibora import Vibora, Response

app = Vibora()

@app.route('/')
def home():
    return Response(b'Hello World')

if __name__ == '__main__':
    def log_handler(msg, level):
        # Redirecting the msg and level to logging library.
        getattr(logging, level)(msg)
        print(f'Msg: {msg} / Level: {level}')

    app.run(logging=log_handler)
```


# Configuration

Configuration handling in Vibora is simple thanks to components.

In your init script (usually called run.py) you can load environment variables, config files or whatever and register a config class as a new component and that's all.

This method is a little bit harder for beginners when compared to the Django approach but it's way more flexible and allows you to build whatever suits you better.

Here goes a practical example:

1\) Create a file called config.py

```python
import aioredis


class Config:
    def __init__(self, config: dict):
        self.port = config['port']
        self.host = config['host']
        self.redis_host = config['redis']['host']
```

2\) Create a file called api.py

```python
from vibora import Vibora
from vibora.blueprints import Blueprint
from vibora.hooks import Events
from aioredis import ConnectionsPool
from config import Config

api = Blueprint()


@api.route('/')
async def home(pool: ConnectionsPool):
    await pool.set('my_key', 'any_value')
    value = await pool.get('my_key')
    return Response(value.encode())


@api.handle(Events.BEFORE_SERVER_START)
async def initialize_db(app: Vibora, config: Config):

    # Creating a pool of connection to Redis.
    pool = await aioredis.create_pool(config.redis_host)

    # In this case we are registering the pool as a new component
    # but if you find yourself using too many components
    # feel free to wrap them all inside a single component
    # so you don't need to repeat yourself in every route.
    app.components.add(pool)
```

3\) Now create a file called config.json

```javascript
{
    "host": "0.0.0.0",
    "port": 8000,
    "redis_host": "127.0.0.1"
}
```

4\) Now create a file called run.py

```python
import json
from vibora import Vibora
from api import api
from config import Config


if __name__ == "__main__":
    # Creating a new app
    app = Vibora()

    # Registering our API
    app.add_blueprint(api, prefixes={'v1': '/v1'})

    # Opening the configuration file.
    with open('config.json') as f:

        # Parsing the JSON configs.
        config = Config(json.load(f))

        # Registering the config as a component so you can use it
        # later on (as we do in the "before_server_start" hook)
        app.components.add(config)

        # Running the server.
        app.run(host=config.host, port=config.port)
```

The previous example loads your configuration from JSON files, but other approaches, such as environment variables, can be used.

Notice that we register the config instance as a component because databases drivers, for example, often need to be instantiated after the server is forked so you'll need the config after the "run script".

Also, our config class in this example is a mere wrapper for our JSON config but in a real app, you could be using the config class as a components wrapper. You'll just need to add references to many important components so you don't need to repeat yourself by importing many different components in every route.


# Deployment

Vibora is not a WSGI compatible framework because of its async nature. Its own http server is built to battle so deployment is far easier than with other frameworks because there is no need for Gunicorn/uWSGI.

One may argue that Gunicorn/uWSGI are battle proven solutions and that's true but they also bring different applications behaviors between dev/prod environments and still need a battle tested server as Nginx in front of them.

The recommend approach to freeze a Vibora app is using docker, this way you can build a frozen image locally in your machine, test it and upload to wherever you host. This way you skip all python packaging problems that you'll find trying to build reproducible deployments between different machines.


# HTTP Client


# Session


# Useful Examples


# Extensions

Under construction


# Contributing

## Contributing

Vibora is developed on GitHub and pull requests are welcome but there are few guidelines:

1\) Introduction of new external dependencies is highly discouraged and will probably not be merged.

2\) Patches that downgrade the overall framework performance, unless security/fix ones, will need to prove great value in functionality to be merged.

3\) Bug fixes must include tests that fail/pass in respective versions.

4\) PEP 8 must be followed with the exception of the max line size which is currently 120 instead of 80 chars wide.

## Reporting an issue

1\) Describe what you expected to happen and what actually happens.

2\) If possible, include a minimal but complete example to help us reproduce the issue.

3\) We'll try to fix it as soon as possible but be in mind that Vibora is open source and you can probably submit a pull request to fix it even faster.

## First time setup

1\) Clone Vibora repository.

2\) Create a virtualenv and install the dependencies listed on requirements.txt

3\) Run build.py (Vibora has a lot of cython extensions and this file helps to build them so you can test your code without the need to install or compile libraries manually.


# FAQ

## Why Vibora ?

* I needed a framework like Flask but async by design.
* Sanic is a good idea with questionable design choices (IMHO).
* Aiohttp is solid (and well thought) but I dislike some interfaces and I think many of them could be user-friendlier.
* I was unaware of Quart and I have mixed feelings about being **compatible** with Flask.
* Japronto is currently a proof of concept, a very impressive one.
* Apistar, although I like it, is far away from being like Flask.
* I don't like Tornado APIs, they did an awesome job don't get me wrong.
* Big Upload/Downloads is a pain the ass in most frameworks thanks to WSGI.
* Flask/Django are sync and always will. Don't get me wrong, being sync isn't bad but it just doesn't fit in some situations. You can do whatever magic you want to make them async but sync interfaces like "request.json" will haunt you.
* I'm a big fan of type hints and very few projects use them.
* And finally because history always repeats itself and here we are, again, with another framework.

## Where the performance comes from ?

* Cython. Critical framework pieces are written Cython so it can leverage "C speed" in critical stuff.
* Common tasks as schema validation, template rendering and other stuff were made builtin in the framework, written from scratch with performance in mind.

## Is it compatible with PyPy ?

* No. PyPy's poor C extensions compatibility (performance-wise) is it's biggest problem.

  Vibora would need to drop its C extensions or have duplicate implementations (Cython powered X pure Python).

  In the end I would bet that Vibora on PyPy would still be slower than the Cython-powered version.

  I'm open to suggestions and I'm watching PyPy closely so who knows.

## Why not use Jinja2 ?

* Jinja2 was not built with async in mind.
* I would need to write a cython compiler for it anyways (Vibora one is in-progress).
* I want a bit more freedom in the template syntax.
* And of course: because it looked like an exciting challenge.

## Where is Japronto on benchmarks ?

* Vibora was almost twice as fast before network flow control was a concern, what that means is that it is very easy to write a fast server but not so easy to build a stable one.
* Although Japronto inspired some pieces of this framework it's missing a huge chunk of fixes and features.
* The author of the framework does not encourage the usage of it and so do I.
* Japronto may be faster than Vibora on naked benchmarks thanks to impressive hand-coded C and faster HTTP parser (pico X noyent).
* Vibora may use "picohttparser" in the future but right now I don't think it's a wise move because it's less battle tested.
* Hand-coded C extensions can be a nightmarish hell to non-expert C devs so I'm not willing to replace Cython with baby cared C code. Still I'm willing to replace Cython with Rust extensions if they get stable enough.

## Why don't you export the template engine into a new project ?

* If people show interest, why not.

## What about Trio ?

* Trio has some interesting concepts and although it's better

  than asyncio in overall I'm not sure about it. The python async community

  is still young and splitting it is not good. We already have a bunch

  of libraries and uvloop so it's hard to move now. I would like to see

  some of it's concepts implemented on top of asyncio but that needs some

  serious creativity because of asyncio design.

## Can we make Vibora faster ?

* Sure. I have a bunch of ideas but I'm a one man army. Are you willing to help me ? :)


# README

## Vibora (Under heavy development)

[Vibora](https://vibora.io) is a **sexy and fast** hybrid (sync/async) Python 3.6+ web framework & server.

* Fast and efficient (probably the fastest Python web framework).
* Schemas / Validation engine. (15x faster than marshmallow)
* Template Engine (AOT compiler, smart cache/reloader, deep inheritance, 2x faster than Jinja2)
* Websockets (RFC 7118 / RFC 6455)
* Components / Nested Blueprints / Domain Based Routes
* Connection Reaper / Self-Healing Workers
* Sessions (encrypted cookies, Redis, Memcache, files)
* Download / Upload streaming
* MultipartForm streaming (Cython finite state machine)
* Caching tools (go fast or go home)
* Complete flow customization (A.k.a Middlewares / Signals / Listeners / Black Magic)
* Static Files (Smart Cache, Range, LastModified, ETags, Streaming)
* Complete Test Framework (async & websocket included)
* Type hints, type hints everywhere.

## Goals

* **Be the fastest Python web framework**.&#x20;
* Windows / Linux / MacOS.
* Correctness > Performance > Easiness of Use > Framework Maintenance.
* Server and Framework, one soul.
* Enjoyable development environment.&#x20;
* Provide a modern Flask alternative to the community.&#x20;

## Usage Example

```python
import asyncio
from vibora import Vibora
from vibora.request import Request
from vibora.responses import JsonResponse

app = Vibora()


@app.route('/')
def home():
    return JsonResponse({'hello': 'world'})


@app.route('/async', methods=['GET'])
async def home_async(request: Request):
    await asyncio.sleep(1)
    print(request.headers)
    return JsonResponse({'hello': 'world'}, status_code=201)


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

## FixME

* Logs
* Router Host/Subdomains
* Async requests timeout.
* Implement a faster, correct and tested router.&#x20;
* Remove requests dependency
* Pause Writing big templates
* Streaming
* Improve URL FOR
* Tests
* Verify compile warnings by messing up any extension path on setup.py
* Check on big uploads
* Command line tools
* Websockets

## Roadmap

* HTTP2 Support.
* Rate Limiting (AWS & Ip Tables integration to help with DDOS)&#x20;
* Cluster-Wide publish/subscribe events API.
* Near real-time API with statistics about the server.
* Native i18n support.
* Auto Reloading
* JIT compiler for user routes.
* Authentication/Authorization Framework

## Special Thanks

* Armin Ronacher. No words needed, this whole framework is based on many of his projects.
* Cython developers. Crazy stuff. Awesome work.&#x20;
* Paweł Piotr Przeradowski. Japronto inspired a lot this framework, thanks bro!

## FAQ

* **Where the performance comes from** ?
  * Cython. Critical framework pieces are written Cython so it can leverage C speed in critical stuff.
  * Common tasks as template rendering, schema validation were made builtin in the framework,&#x20;

    written from scratch with performance in mind.  &#x20;
* **It's Pypy compatible** ?
  * Not yet. But I'll make sure it works on Pypy as soon as Pypy reaches 3.5 stable.
* **Why not use Jinja2** ?
  * It's hell easier to write something from scratch when looking for performance on something&#x20;

    already heavily optimized.
* **Where is Japronto on benchmarks** ?
  * Japronto is a proof of concept. The whole framework is missing a huge chunk of features and fixes.&#x20;

    The author of the framework does not encourage the usage of it and so do I.&#x20;
  * Japronto can be faster than Vibora on naked benchmarks thanks to impressive hand-coded C&#x20;

    and faster HTTP parser (pico X noyent).
  * Vibora does not use "picohttparser" because I don't think it's safe enough and there are bunch of issues/pull&#x20;

    requests waiting years to be fixed.
  * Hand-coded C extensions can be a nightmare hell to non-expert C devs so I'm not&#x20;

    willing to replace Cython with baby cared C code. Still I'm willing to replace Cython with Rust extensions&#x20;

    if they get stable enough.
  * Compare a naked framework against a fully featured framework is just dumb. To give you a reason:&#x20;

    Vibora was 30% faster before security and features were a concern.&#x20;
* **Why don't export the template engine into a new project** ?
  * I'm planning to do so but right now I want to focus on Vibora features/integration.   &#x20;
* **Can we make it even faster** ?
  * Sure! I have a hell bunch of ideas but I'm one man army. Are you willing to help me ? :)


# vendor


# HTTP Parser

![Build Status](https://api.travis-ci.org/nodejs/http-parser.svg?branch=master)

This is a parser for HTTP messages written in C. It parses both requests and responses. The parser is designed to be used in performance HTTP applications. It does not make any syscalls nor allocations, it does not buffer data, it can be interrupted at anytime. Depending on your architecture, it only requires about 40 bytes of data per message stream (in a web server that is per connection).

Features:

* No dependencies
* Handles persistent streams (keep-alive).
* Decodes chunked encoding.
* Upgrade support
* Defends against buffer overflow attacks.

The parser extracts the following information from HTTP messages:

* Header fields and values
* Content-Length
* Request method
* Response status code
* Transfer-Encoding
* HTTP version
* Request URL
* Message body

## Usage

One `http_parser` object is used per TCP connection. Initialize the struct using `http_parser_init()` and set the callbacks. That might look something like this for a request parser:

```c
http_parser_settings settings;
settings.on_url = my_url_callback;
settings.on_header_field = my_header_field_callback;
/* ... */

http_parser *parser = malloc(sizeof(http_parser));
http_parser_init(parser, HTTP_REQUEST);
parser->data = my_socket;
```

When data is received on the socket execute the parser and check for errors.

```c
size_t len = 80*1024, nparsed;
char buf[len];
ssize_t recved;

recved = recv(fd, buf, len, 0);

if (recved < 0) {
  /* Handle error. */
}

/* Start up / continue the parser.
 * Note we pass recved==0 to signal that EOF has been received.
 */
nparsed = http_parser_execute(parser, &settings, buf, recved);

if (parser->upgrade) {
  /* handle new protocol */
} else if (nparsed != recved) {
  /* Handle error. Usually just close the connection. */
}
```

HTTP needs to know where the end of the stream is. For example, sometimes servers send responses without Content-Length and expect the client to consume input (for the body) until EOF. To tell http\_parser about EOF, give `0` as the fourth parameter to `http_parser_execute()`. Callbacks and errors can still be encountered during an EOF, so one must still be prepared to receive them.

Scalar valued message information such as `status_code`, `method`, and the HTTP version are stored in the parser structure. This data is only temporally stored in `http_parser` and gets reset on each new message. If this information is needed later, copy it out of the structure during the `headers_complete` callback.

The parser decodes the transfer-encoding for both requests and responses transparently. That is, a chunked encoding is decoded before being sent to the on\_body callback.

## The Special Problem of Upgrade

HTTP supports upgrading the connection to a different protocol. An increasingly common example of this is the WebSocket protocol which sends a request like

```
    GET /demo HTTP/1.1
    Upgrade: WebSocket
    Connection: Upgrade
    Host: example.com
    Origin: http://example.com
    WebSocket-Protocol: sample
```

followed by non-HTTP data.

(See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the WebSocket protocol.)

To support this, the parser will treat this as a normal HTTP message without a body, issuing both on\_headers\_complete and on\_message\_complete callbacks. However http\_parser\_execute() will stop parsing at the end of the headers and return.

The user is expected to check if `parser->upgrade` has been set to 1 after `http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied offset by the return value of `http_parser_execute()`.

## Callbacks

During the `http_parser_execute()` call, the callbacks set in `http_parser_settings` will be executed. The parser maintains state and never looks behind, so buffering the data is not necessary. If you need to save certain data for later usage, you can do that from the callbacks.

There are two types of callbacks:

* notification `typedef int (*http_cb) (http_parser*);`

  &#x20; Callbacks: on\_message\_begin, on\_headers\_complete, on\_message\_complete.
* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);`

  &#x20; Callbacks: (requests only) on\_url,

  ```
           (common) on_header_field, on_header_value, on_body;
  ```

Callbacks must return 0 on success. Returning a non-zero value indicates error to the parser, making it exit immediately.

For cases where it is necessary to pass local information to/from a callback, the `http_parser` object's `data` field can be used. An example of such a case is when using threads to handle a socket connection, parse a request, and then give a response over that socket. By instantiation of a thread-local struct containing relevant data (e.g. accepted socket, allocated memory for callbacks to write into, etc), a parser's callbacks are able to communicate data between the scope of the thread and the scope of the callback in a threadsafe manner. This allows http-parser to be used in multi-threaded contexts.

Example:

```c
 typedef struct {
  socket_t sock;
  void* buffer;
  int buf_len;
 } custom_data_t;


int my_url_callback(http_parser* parser, const char *at, size_t length) {
  /* access to thread local custom_data_t struct.
  Use this access save parsed data for later use into thread local
  buffer, or communicate over socket
  */
  parser->data;
  ...
  return 0;
}

...

void http_parser_thread(socket_t sock) {
 int nparsed = 0;
 /* allocate memory for user data */
 custom_data_t *my_data = malloc(sizeof(custom_data_t));

 /* some information for use by callbacks.
 * achieves thread -> callback information flow */
 my_data->sock = sock;

 /* instantiate a thread-local parser */
 http_parser *parser = malloc(sizeof(http_parser));
 http_parser_init(parser, HTTP_REQUEST); /* initialise parser */
 /* this custom data reference is accessible through the reference to the
 parser supplied to callback functions */
 parser->data = my_data;

 http_parser_settings settings; /* set up callbacks */
 settings.on_url = my_url_callback;

 /* execute parser */
 nparsed = http_parser_execute(parser, &settings, buf, recved);

 ...
 /* parsed information copied from callback.
 can now perform action on data copied into thread-local memory from callbacks.
 achieves callback -> thread information flow */
 my_data->buffer;
 ...
}
```

In case you parse HTTP message in chunks (i.e. `read()` request line from socket, parse, read half headers, parse, etc) your data callbacks may be called more than once. Http-parser guarantees that data pointer is only valid for the lifetime of callback. You can also `read()` into a heap allocated buffer to avoid copying memory around if this fits your application.

Reading headers may be a tricky task if you read/parse headers partially. Basically, you need to remember whether last header callback was field or value and apply the following logic:

```
(on_header_field and on_header_value shortened to on_h_*)
 ------------------------ ------------ --------------------------------------------
| State (prev. callback) | Callback   | Description/action                         |
 ------------------------ ------------ --------------------------------------------
| nothing (first call)   | on_h_field | Allocate new buffer and copy callback data |
|                        |            | into it                                    |
 ------------------------ ------------ --------------------------------------------
| value                  | on_h_field | New header started.                        |
|                        |            | Copy current name,value buffers to headers |
|                        |            | list and allocate new buffer for new name  |
 ------------------------ ------------ --------------------------------------------
| field                  | on_h_field | Previous name continues. Reallocate name   |
|                        |            | buffer and append callback data to it      |
 ------------------------ ------------ --------------------------------------------
| field                  | on_h_value | Value for current header started. Allocate |
|                        |            | new buffer and copy callback data to it    |
 ------------------------ ------------ --------------------------------------------
| value                  | on_h_value | Value continues. Reallocate value buffer   |
|                        |            | and append callback data to it             |
 ------------------------ ------------ --------------------------------------------
```

## Parsing URLs

A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`. Users of this library may wish to use it to parse URLs constructed from consecutive `on_url` callbacks.

See examples of reading in headers:

* [partial example](http://gist.github.com/155877) in C
* [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C
* [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript


# Introduction

Make sure you are using `Python 3.6+` because Vibora takes advantage of some new Python features.

1. Install Vibora: `pip install vibora[fast]`

> It's highly recommended to install Vibora inside a virtualenv.
>
> In case you have trouble with Vibora dependencies: `pip install vibora` to install it without the extra libraries.

1. Create a file called `anything.py` with the following code:

```python
from vibora import Vibora, JsonResponse

app = Vibora()


@app.route('/')
async def home():
    return JsonResponse({'hello': 'world'})

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8000)
```

1. Run the server: `python3 anything.py`
2. Open your browser at `http://127.0.0.1:8000`

## Creating a project

The previous example was just to show off how easy is it to spin up a server.

The recommended way to start a new project is by letting Vibora do it for you. Vibora is also a command-line tool, try it out: `vibora new project_name`


# Routing

## Routing

Routing is the core of any web framework because it allows the user to map URL endpoints to functions.

```python
@app.route("/home", methods=['GET'])
async def home():
    return Response(b'123')
```

> In this example you are mapping every HTTP request with a `GET` method and a path equals to `/home` to `async def home()`.

## Request Parameters

Often parts of an URL have a special meaning, for example, specifying which product should be displayed.

```python
@app.route('/product/<product_id>')
async def show_product(product_id: int):
    return Response(f'Chosen product: {product_id}'.encode())
```

Not usually you'll need something more sophisticated. Vibora patterns are actually regular expressions.

```python
import re

@app.route('/product/(?P<product_id>[0-9]+)')
async def show_product(product_id: int):
    return Response(f'Chosen product: {product_id}'.encode())
```

## Virtual Hosts

Maybe you have different domains and you want to host them all with a single Vibora application. So `http://docs.vibora.io/` and `http://vibora.io/` would hit the same application but return different responses based on the `HTTP host header`. Vibora makes it very easy thanks to the `hosts` attribute.

```python
@app.route('/', hosts=['docs.vibora.io'])
async def docs():
    return Response(b'Docs')

@app.route('/', hosts=['vibora.io'])
async def home():
    return Response(b'Home')
```

To avoid repeating the `hosts` attribute for every route, you can group routes using a Blueprint.

```python
from vibora.blueprints import Blueprint
from vibora.responses import Response


docs = Blueprint(hosts=['docs.vibora.io'])
main = Blueprint(hosts=['vibora.io'])


@docs.route('/')
async def docs():
    return Response(b'docs')


@main.route('/')
async def home():
    return Response(b'main')
```

## Router Strategies

A common source of headaches in URL routing are ending slashes.

Let's take the path `/home` and `/home/` for example.

In a web environment these are two completely different paths, it's up to the server to interpret those as the same or not.

Vibora has three different strategies to deal with this problem:

1. **Strict**. Does nothing. If you map your endpoints ending with

   slashes then if you try to access `/home` instead of `/home/`

   you'll get a 404 response.
2. **Redirect (Default)**. If you map your route as `/home` then

   Vibora will return a 302 response if someone tries to access `/home/`

   and vice-versa.
3. **Clone**. This one is similar to redirect but instead of a 302 it'll

   return the same response for both routes.

Configuration example:

```python
from vibora import Vibora
from vibora.router import RouterStrategy

app = Vibora(router_strategy=RouterStrategy.STRICT)
```

## Caching

Caching can be a tremendous ally when handling performance issues. Imagine an API that does a read-only query being hit by 10k requests/sec, this means that you are stressing your database at 10k queries/sec.

If you start caching the response for at least one second you drop from 10k queries/sec to 1 query per second. That's a huge improvement with almost no effort.

Vibora has some internal optimizations to speed-up cached APIs so instead of handling it all by ourselves, you should use the `CacheEngine`.

```python
from vibora import Vibora, Response, Request
from vibora.cache import CacheEngine

app = Vibora()


class YourCacheEngine(CacheEngine):
    async def get(self, request: Request):
        return self.cache.get(request.url)

    async def store(self, request: Request, response):
        self.cache[request.url] = response


@app.route('/', cache=YourCacheEngine(skip_hooks=True))
def home():
    return Response(b'Hello World')
```

> Notice the "skip\_hooks" parameter which makes cached responses to skip any listeners/hooks. Sometimes this is useful, often not, use wisely.

## Static Files

Vibora is fast enough to host static files and it tries hard to implement the same features as some battle proven solutions like Nginx.

By default Vibora will seek for a directory called "static" in the same parent directory related to the file that created Vibora app instance.

You can configure the `StaticHandler` as bellow:

> All parameters are optional.

```python
from vibora.static import StaticHandler

app = Vibora(
    static=StaticHandler(
        paths=['/your_static_dir', '/second_static_dir'],
        host='static.vibora.io',
        url_prefix='/static',
        max_cache_size=1 * 1024 * 1024
    )
)
```

> **Host** parameter can be used to only serve static files when the Host header matches this specific host.
>
> **max\_cache\_size** specifies the amount of memory that Vibora may invest into optimizations.


# Components

## Components

Every app has some hot objects that should be available almost everywhere. Maybe they are database instances, maybe request objects. Vibora call these objects `components`

For now you should pay close attention to the `Request` component:

This is the most important component and will be everywhere in your app. It holds all information related to the current request and also some useful references like the current application and route.

You can ask for components in your route by using type hints:

```python
from vibora import Vibora, Request, Response

app = Vibora()

@app.route('/')
async def home(request: Request):
    print(request.headers)
    return Response(b'123')
```

The request object has a special method that allows you to ask for more components as you go.

```python
from vibora import Vibora, Request, Response
from vibora import Route

app = Vibora()

@app.route('/')
async def home(request: Request):
    current_route = request.get_component(Route)
    return Response(current_route.pattern.encode())
```

> By now you should have noticed that Vibora is smart enough to know which components do you want in your routes so your routes may not receive any parameters at all or ask as many components do you wish.

## Adding custom components

Vibora was designed to avoid global magic (unlike Flask for example) because it makes testing harder and more prone to errors specially in async environments.

To help with this, Vibora provides an API where you can register objects to later use.

This means they are correctly encapsulated into a single app object, allowing many apps instances to work concurrently, encouraging the use of type hints which brings many benefits in the long-term and also make your routes much easier to test.

```python
from vibora import Vibora, Request, Response
from vibora import Route

# Config will be a new component.
class Config:
    def __init__(self):
        self.name = 'Vibora Component'

app = Vibora()

# Registering the config instance.
app.add_component(Config())

@app.route('/')
async def home(request: Request, config: Config):
    """
    Notice that if you specify a parameter of type "Config"
    Vibora will automatically provide the config instance registered previously.
    Instead of adding global variables you can now register new components,
    that are easily testable and accessible.
    """
    # You could also ask for the Config component at runtime.
    current_config = request.get_component(Config)
    assert current_config is config
    return Response(config.name)
```


# Request Component

## Request Component

The request component holds all the information related to the current request. Json, Forms, Files everything can be accessed through it.

## Receiving JSON

```python
from vibora import Vibora, Request
from vibora.responses import JsonResponse

app = Vibora()

@app.route('/')
async def home(request: Request):
    values = await request.json()
    print(values)
    return JsonResponse(values)
app.run()
```

Note that `request.json()` is actually a coroutine that needs to be **awaited**, this design prevents the entire JSON being uploaded in-memory before the route requires it.

## Uploaded Files

Uploaded files by multipart forms can be accessed by field name in `request.form` or through the `request.files` list. Both methods are co-routines that will consume the `request.stream` and store the file in-disk if it's too big to keep in-memory.

You can control the memory/disk usage of uploaded files by calling `request.load_form(threshold=1 * 1024 * 1024)` explicitly, in this case files bigger than 1mb will be flushed to disk.

> Please be aware that the form threshold does not passthrough the max\_body\_size limit so you'll still need to configure your route properly.

Instead of pre-parsing the entire form you could call `request.stream_form()` and deal with every uploaded field as it arrives by the network. This is good when you don't want files hitting the disk and in some scenarios allows you to waste less memory by doing way more coding yourself.

```python
import uuid
from vibora import Vibora, Request
from vibora.responses import JsonResponse

app = Vibora()

@app.route('/', methods=['POST'])
async def home(request: Request):
    uploaded_files = []
    for file in (await request.files):
        file.save('/tmp/' + str(uuid.uuid4()))
        print(f'Received uploaded file: {file.filename}')
        uploaded_files.append(file.filename)
    return JsonResponse(uploaded_files)
```

## Querystring

```python
from vibora import Vibora, Response, Request

app = Vibora()

@app.route('/')
async def home(request: Request):
    print(request.args)
    return Response(f'Name: {request.args['name']}'.encode())
```

> A request to <http://{address}/?name=vibora> would return 'Name: vibora'

## Raw Stream

Sometimes you need a low-level access to the HTTP request body, `request.stream` method provides an easy way to consume the stream by ourself.

```python
from vibora import Vibora, Request, Response

app = Vibora()

@app.route('/', methods=['POST'])
async def home(request: Request):
    content = await request.stream.read()
    return Response(content)
```

## URLs

Ideally you shouldn't need to deal with the URL directly but sometimes that's the only way. The request object carries two properties that can help you:

`request.url`: Raw URL

`request.parsed_url`: A parsed URL where you can access the path, host and all URL attributes easily. The URL is parsed by a fast Cython parser so there is no need to you re-invent the wheel.

```python
from vibora import Vibora, Request
from vibora.responses import JsonResponse

app = Vibora()

@app.route('/')
async def home(request: Request):
    return JsonResponse(
        {'url': request.url, 'parsed_url': request.parsed_url}
    )
```


# Responses

## Responses

Each route must return a Response object, the protocol will use these objects to encode the HTTP response and send through the socket.

There are many different response types but they all inherit from the base Response class.

Bellow there are the most important ones:

## JSON Response

Automatically dumps Python objects and adds the correct headers to match the JSON format.

```python
from vibora import Vibora, JsonResponse

app = Vibora()

@app.route('/')
async def home():
    return JsonResponse({'hello': 'world})
```

## Streaming Response

Whenever you don't have the response already completely ready, be it because you don't want to waste memory by buffering, be it because you want the client to start receiving the response as soon as possible, a StreamingResponse will be more appropriate.

**A StreamingResponse receives a coroutine that yield bytes.**

Differently from simple responses, streaming ones have more timeout options because they are often long running tasks. Usually a route timeout works until the client consumes the entire response but with streaming responses this is not true. After the route return a StreamingResponse two new timeouts options take its place.

> **complete\_timeout: int**: How many seconds the client have to consume the **entire** response. So if you set it to 30 seconds the client will have 30 seconds to consume the entire response, in case not, the connection will be closed abruptly to avoid DOS attacks. You may set it to zero and completely disable this timeout, when chunk\_timeout is properly configured this is a reasonable choice.
>
> **chunk\_timeout: int**: How many seconds the client have to consume each response chunk. Lets say your function produces 30 bytes per yield and the chunk\_timeout is 10 seconds. The client will have 10 seconds to consume the 30 bytes, in case not, the connection will be closed abruptly to avoid DOS attacks.

```python
import asyncio
from vibora import Vibora, StreamingResponse

app = Vibora()

@app.route('/')
async def home():
    async def stream_builder():
        for x in range(0, 5):
            yield str(x).encode()
            await asyncio.sleep(1)

    return StreamingResponse(
           stream_builder, chunk_timeout=10, complete_timeout=30
    )
```

## Response

A raw Response object would fit whenever you need a more customized response.

```python
from vibora import Vibora, Response

app = Vibora()

@app.route('/')
async def home():
    return Response(b'Hello World', headers={'content-type': 'html'})
```


# Data Validation

## Data Validation

Data validation is a common task in any web related activity. Vibora has a module called `schemas` to build, guess what, schemas, and validate your data against them. They are very similar to `marshmallow` and other famous libraries except they have some speedups written in Cython for amazing performance.

Schemas are also asynchronous meaning that you can do database checkups and everything in a single place, something that cannot be done in other libraries which forces you to split your validation logic between different places.

## Usage Example

### Declaring your schema

```python
from vibora.schemas import Schema, fields
from vibora.schemas.exceptions import ValidationError
from vibora.schemas.validators import Length, Email
from vibora.context import get_component
from .database import Database


class AddUserSchema(Schema):

    @staticmethod
    async def unique_email(email: str):
        # You can get any existent component by using "vibora.context"
        database = get_component(Database)
        if await database.exists_user(email):
            raise ValidationError(
                'There is already a registered user with this e-mail'
            )

    # Custom validations can be done by passing a list of functions
    # to the validators keyword param.
    email: str = fields.Email(pattern='.*@vibora.io',
            validators=[unique_email]
    )

    # There are many builtin validation helpers as Length().
    password: str = fields.String(validators=[Length(min=6, max=20)])

    # In case you just want to enforce the type of a given field,
    # a type hint is enough.
    name: str
```

### Using your schema

```python
from vibora import Request, Blueprint, JsonResponse
from .schemas import AddUserSchema
from .database import Database

users_api = Blueprint()

@users_api.route('/add')
async def add_user(request: Request, database: Database):

    # In case the schema is invalid an exception will be raised
    # and catched by an exception handler, this means you don't need to
    # repeat yourself about handling errors. But in case you want to
    # customize the error message feel free to catch the exception
    # and handle it your way. "from_request" method is just syntatic sugar
    # to avoid calling request.json() yourself.
    schema = await AddUserSchema.from_request(request)

    # By now our data is already valid and clean,
    # so lets add our user to the database.
    database.add_user(schema)

    return JsonResponse({'msg': 'User added successfully'})
```

> Type hints must always be provided for each field. In case the field is always required and do not have any custom validation the type hint alone will be enough to Vibora build your schema.


# Fields

## Fields

Vibora has a special class called "Field" to represent each field of a schema. You can build any kind of validation rules using this class but to avoid repeat yourself there a few builtin ones. There are a few must-know attributes of this class:

1\) **required** -> By default all declared fields in a schema are required which means they must be present in the validation values. If you have optional fields you must explicitely declare this as `Field(required=False)`

2\) **load\_from** -> Sometimes is useful to deal with friendly names inside a schema but to ofuscate them outside outside your app, by using the `load_from` parameter you can specify where to load this field from or even load two different fields from the same key.

3\) **default** -> A default value in case the key is missing or the value is null.

4\) **validators** -> A list of functions to validate the current value against. This functions can be async or sync and receive one up to two parameters. In case it receives a single parameter then Vibora will pass only the current value to it. In case it receive two parameters the context of the schema will be also provided. The exception `ValidationError` must be raised to notify the schema that this field is invalid, returning values are ignored.

## StringField

Validates if the given value is a valid string.

```python
import uuid
from vibora.schemas import Schema, fields
from vibora.schemas.validators import Length

class NewUserSchema(Schema):

    name: str = fields.String(
        required=False,
        validators=[Length(min=3, max=30)],
        default=lambda: str(uuid.uuid4()),
        strict=False
    )
```

> There is a special attribute called `strict` to allow this field to cast integers and similar types to a string instead of raising an error.


# Events

Hooks are functions that are called after an event.

Let's suppose you want to add a header to every response in your app. Instead of manually editing every single route in your app you can just register a listener to the event "BeforeResponse" and inject the desired headers.

Below is a fully working example:

```python
from vibora import Vibora, Response
from vibora.hooks import Events

app = Vibora()

@app.route('/')
async def home():
    return Response(b'Hello World')

@app.handle(Events.BEFORE_RESPONSE)
async def before_response(response: Response):
    response.headers['x-my-custom-header'] = 'Hello :)'

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

Hooks can halt a request and prevent a route from being called, completely modify the response, handle app start/stop functionalities, initialize components and do all kind of stuff.

> The golden rule is: If you don't want to modify the request flow (like halting requests) you don't want to return anything in your function. Of course that depends on which event you are listening to.


# Testing

Testing is the most important part of any project with considerably size and yet of one of the most ignored steps.

Vibora has a builtin and fully featured async HTTP client and a simple test framework to make it easier for you as in the example bellow:

```python
from vibora import Vibora, Response
from vibora.tests import TestSuite

app = Vibora()


@app.route('/')
async def home():
    return Response(b'Hello World')


class HomeTestCase(TestSuite):
    def setUp(self):
        self.client = app.test_client()

    async def test_home(self):
        response = await self.client.get('/')
        self.assertEqual(response.content, b'Hello World')
```


# Advanced Tips

Under construction


# Template Engine

Although server-side rendering is not main-stream nowadays, Vibora has its own template engine. The idea was to build something like Jinja2 but with async users as first class citizens. Jinja2 is already heavily optimized but we tried to beat it in benchmarks.

Jinja2 also prevents you to pass parameters to functions and a few other restrictions which are often a good idea but don't comply with Vibora philosophy of not getting into your way.

The syntax is pretty similar to Jinja2, templates are often compatible.

The render process is async which means you can pass coroutines to your templates and call them as regular functions, Vibora will do the magic.

VTE has hot-reloading so we can swap templates at run-time. This is enabled by default in debug mode so you have a fast iteration cycle while building your app.

Although VTE **do not aim to be sandboxed** it tries hard to prevent the templates from leaking access to outside context.


# Syntax

VTE syntax is basically split between two things: Tags and Expressions.

```markup
<html>
    <head>
        <title> {{ title }} </title>
    </head>
    <body>
        <ul>
            {% for user in users %}
                <li> {{ user.name}} </li>
            {% endfor %}
        </ul>
    </body>
</html>
```

1\) Expressions are delimited by "{ { variable\_name } }" and they are used to print data.

2\) Tags are delimited by "{ % tag\_name % }" and they are used to express intents like loops, conditionals, etc.

> There are many default tags and you can create your own too by adding an extension, you can also customize the markers so instead of "{%" you could use "#\[" or whatever do you think it's best.


# Extending

WIP...


# Performance

WIP...


# Logging

Vibora has a simple logging mechanism to avoid locking you into our library of choice.

You must provide a function that receives two parameters: a msg and a logging level (that matches logging standard library for usability sake).

That's all.

It's up to you to choose what to do with logging messages.

```python
import logging
from vibora import Vibora, Response

app = Vibora()

@app.route('/')
def home():
    return Response(b'Hello World')

if __name__ == '__main__':
    def log_handler(msg, level):
        # Redirecting the msg and level to logging library.
        getattr(logging, level)(msg)
        print(f'Msg: {msg} / Level: {level}')

    app.run(logging=log_handler)
```


# Configuration

Configuration handling in Vibora is simple thanks to components.

In your init script (usually called run.py) you can load environment variables, config files or whatever and register a config class as a new component and that's all.

This method is a little bit harder for beginners when compared to the Django approach but it's way more flexible and allows you to build whatever suits you better.

Here goes a practical example:

1\) Create a file called config.py

```python
import aioredis


class Config:
    def __init__(self, config: dict):
        self.port = config['port']
        self.host = config['host']
        self.redis_host = config['redis']['host']
```

2\) Create a file called api.py

```python
from vibora import Vibora
from vibora.blueprints import Blueprint
from vibora.hooks import Events
from aioredis import ConnectionsPool
from config import Config

api = Blueprint()


@api.route('/')
async def home(pool: ConnectionsPool):
    await pool.set('my_key', 'any_value')
    value = await pool.get('my_key')
    return Response(value.encode())


@api.handle(Events.BEFORE_SERVER_START)
async def initialize_db(app: Vibora, config: Config):

    # Creating a pool of connection to Redis.
    pool = await aioredis.create_pool(config.redis_host)

    # In this case we are registering the pool as a new component
    # but if you find yourself using too many components
    # feel free to wrap them all inside a single component
    # so you don't need to repeat yourself in every route.
    app.components.add(pool)
```

3\) Now create a file called config.json

```javascript
{
    "host": "0.0.0.0",
    "port": 8000,
    "redis_host": "127.0.0.1"
}
```

4\) Now create a file called run.py

```python
import json
from vibora import Vibora
from api import api
from config import Config


if __name__ == "__main__":
    # Creating a new app
    app = Vibora()

    # Registering our API
    app.add_blueprint(api, prefixes={'v1': '/v1'})

    # Opening the configuration file.
    with open('config.json') as f:

        # Parsing the JSON configs.
        config = Config(json.load(f))

        # Registering the config as a component so you can use it
        # later on (as we do in the "before_server_start" hook)
        app.components.add(config)

        # Running the server.
        app.run(host=config.host, port=config.port)
```

The previous example loads your configuration from JSON files, but other approaches, such as environment variables, can be used.

Notice that we register the config instance as a component because databases drivers, for example, often need to be instantiated after the server is forked so you'll need the config after the "run script".

Also, our config class in this example is a mere wrapper for our JSON config but in a real app, you could be using the config class as a components wrapper. You'll just need to add references to many important components so you don't need to repeat yourself by importing many different components in every route.


# Deployment

Vibora is not a WSGI compatible framework because of its async nature. Its own http server is built to battle so deployment is far easier than with other frameworks because there is no need for Gunicorn/uWSGI.

One may argue that Gunicorn/uWSGI are battle proven solutions and that's true but they also bring different applications behaviors between dev/prod environments and still need a battle tested server as Nginx in front of them.

The recommend approach to freeze a Vibora app is using docker, this way you can build a frozen image locally in your machine, test it and upload to wherever you host. This way you skip all python packaging problems that you'll find trying to build reproducible deployments between different machines.


# HTTP Client


# Session


# Useful Examples


# Extensions

Under construction


# Contributing

## Contributing

Vibora is developed on GitHub and pull requests are welcome but there are few guidelines:

1\) Introduction of new external dependencies is highly discouraged and will probably not be merged.

2\) Patches that downgrade the overall framework performance, unless security/fix ones, will need to prove great value in functionality to be merged.

3\) Bug fixes must include tests that fail/pass in respective versions.

4\) PEP 8 must be followed with the exception of the max line size which is currently 120 instead of 80 chars wide.

## Reporting an issue

1\) Describe what you expected to happen and what actually happens.

2\) If possible, include a minimal but complete example to help us reproduce the issue.

3\) We'll try to fix it as soon as possible but be in mind that Vibora is open source and you can probably submit a pull request to fix it even faster.

## First time setup

1\) Clone Vibora repository.

2\) Create a virtualenv and install the dependencies listed on requirements.txt

3\) Run build.py (Vibora has a lot of cython extensions and this file helps to build them so you can test your code without the need to install or compile libraries manually.


# FAQ

## Why Vibora ?

* I needed a framework like Flask but async by design.
* Sanic is a good idea with questionable design choices (IMHO).
* Aiohttp is solid (and well thought) but I dislike some interfaces and I think many of them could be user-friendlier.
* I was unaware of Quart and I have mixed feelings about being **compatible** with Flask.
* Japronto is currently a proof of concept, a very impressive one.
* Apistar, although I like it, is far away from being like Flask.
* I don't like Tornado APIs, they did an awesome job don't get me wrong.
* Big Upload/Downloads is a pain the ass in most frameworks thanks to WSGI.
* Flask/Django are sync and always will. Don't get me wrong, being sync isn't bad but it just doesn't fit in some situations. You can do whatever magic you want to make them async but sync interfaces like "request.json" will haunt you.
* I'm a big fan of type hints and very few projects use them.
* And finally because history always repeats itself and here we are, again, with another framework.

## Where the performance comes from ?

* Cython. Critical framework pieces are written Cython so it can leverage "C speed" in critical stuff.
* Common tasks as schema validation, template rendering and other stuff were made builtin in the framework, written from scratch with performance in mind.

## Is it compatible with PyPy ?

* No. PyPy's poor C extensions compatibility (performance-wise) is it's biggest problem.

  Vibora would need to drop its C extensions or have duplicate implementations (Cython powered X pure Python).

  In the end I would bet that Vibora on PyPy would still be slower than the Cython-powered version.

  I'm open to suggestions and I'm watching PyPy closely so who knows.

## Why not use Jinja2 ?

* Jinja2 was not built with async in mind.
* I would need to write a cython compiler for it anyways (Vibora one is in-progress).
* I want a bit more freedom in the template syntax.
* And of course: because it looked like an exciting challenge.

## Where is Japronto on benchmarks ?

* Vibora was almost twice as fast before network flow control was a concern, what that means is that it is very easy to write a fast server but not so easy to build a stable one.
* Although Japronto inspired some pieces of this framework it's missing a huge chunk of fixes and features.
* The author of the framework does not encourage the usage of it and so do I.
* Japronto may be faster than Vibora on naked benchmarks thanks to impressive hand-coded C and faster HTTP parser (pico X noyent).
* Vibora may use "picohttparser" in the future but right now I don't think it's a wise move because it's less battle tested.
* Hand-coded C extensions can be a nightmarish hell to non-expert C devs so I'm not willing to replace Cython with baby cared C code. Still I'm willing to replace Cython with Rust extensions if they get stable enough.

## Why don't you export the template engine into a new project ?

* If people show interest, why not.

## What about Trio ?

* Trio has some interesting concepts and although it's better

  than asyncio in overall I'm not sure about it. The python async community

  is still young and splitting it is not good. We already have a bunch

  of libraries and uvloop so it's hard to move now. I would like to see

  some of it's concepts implemented on top of asyncio but that needs some

  serious creativity because of asyncio design.

## Can we make Vibora faster ?

* Sure. I have a bunch of ideas but I'm a one man army. Are you willing to help me ? :)


