dovcha 0.2.0
A simple Python web framework for building web applications.
License: MIT
Requires Python: >=3.9.0


#DOVCHA: Python Web Framework build for learning purposes

![puspose](https://img.shields.io/badge/purpose-learning-green)
![PyPI - Version](https://img.shields.io/pypi/v/dovcha)



DOVCHA is a Python web framework built for learning purposes.

It's a WSGI framework and can be used with any WSGI application server such as Gunicorn.

## Installation

```shell
pip install dovcha 
```

## How to use it 

### Basic usage:    

```python
from dovcha.api import DovchaApp
app = DovchaApp()

@app.route("/home")
def home(request, response):
    response.text = "Hello from the HOME page"


@app.route("/hello{name}")
def greeting(request, response, name):
    response.text = f"Hello, {name}"


@app.route("/book")
class BookResource:
    def get(self, req, resp):
        resp.text = "Books Page"

    def post(self, req, resp):
        resp.text = "Endpoint to create a book"



@app.route("/template")
def template_handler(request, response):
    response.html = app.template(
        "home.html",
        context={"new_title": "New Title", "new_body": "New body"}
    )
```

### Unit Tests


The recommended way of writing unit tests is with [pytest](https://docs.pytest.org/en/latest). There are two built in fixtures that you may want to use when writing unit test with Dovcha. The first one is 'app' which is an instance of the main 'API' class:

```python

def test_route_overlap_throws_exception(app):
    @app.route("/")
    def home(req, resp):
        resp.text = "Welcome Home."

    with pytest.raises(AssertionError):
         @app.route("/")
    def home2(req, resp):
        resp.text = "Welcome Home2."

```


The other one is 'client' that you can use to send HTTP requests to your handlers. It is based on the famous [requests] (https://requests.readthedocs.io/) and it should feel very familiar:        

```python
def test_parameterized_route(app, client):
    @app.route("/{name}")
    def hello(req, resp, name):
        resp.text = f"hey {name}"


    assert client.get("https//testserver/matthew").text == "hey matthew"

```


## Templates


The default folder for templates is 'templates'. You can change it when initializing the main 'API()' class:

```python
app = API(templates_dir="templates_dir_name")
```


Then you can use HTML files in that folder like so in a handler:

```python
@app.route("/show/template")
def handler_with_template(req, resp):
    resp.html = app.template(
        "example.html", content={"title":"Awesome Framework", "body":"welcome to the future!"}
    )
```


## Static Files


Just like templates, the default folder for static files is 'static' and you can override it:

```python
app = API(static_dir="static_dir_name")
```

Then you can use the files inside this folder in HTML files:

```html
<!DOCTYPE html>
<html lang="en">


<head>
    <meta charset="UTF-8">
    <title>{{title}}</title>

    <link href="/static/main.css" rel="stylesheet" type="text/css">
</head>

<body>
    <h1>{{body}}</h1>
    <p>This is a paragraph</p>

</body>
</html>
```

### Middleware

You can create custom middleware classes by inheriting from the 'dovcha.middleware.Middleware' class and overriding its two methods that are called before and after each request:


```python

from dovcha.api import API
from dovcha.middleware import Middleware


app = API()


class SimpleCustomMiddleware(Middleware):
      def process_request(self, req):
          print("Before dispatch", req.url)

      def process_response(self, req, res):
          print("After dispatch", req.url)



app.add_middleware(SimpleCustomMiddleware)
```