trivela 0.0.5
Trivela Python Web Framework build for learning purpose.
License: MIT
Requires Python: >=3.12.0


# Trivela: Python Web Framework built for learning purposes

![purpose](https://img.shields.io/badge/learining-purpose-blue)
![PyPI](https://img.shields.io/badge/Trivela-8A2BE2)

Trivela is a Python web framework build for learning purposes.

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

## Installation
```shell
pip install trivela

```


## How to use it

### Basic usage:

```python
from trivela.api import API

app = API()

@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 BooksResource:
    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(req, resp):
    resp.body = app.template(
        "index.html", context={"name": "Trivela", "title": "Worst Framework"}).encode()

```

### 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 tests with Trivela. 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("http://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", context={"title": "Bad 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 `trivela.middleware.Middleware` class and overriding its two methods
that are called before and after each request:

```python
from trivela.api import API
from trivela.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)
```
### ORM
You can use `Trivela ORM` to interact with database and perform some basic operations mentioned below:

Connect to the database:
```python
from trivela.orm import Database
db = Database("./demo.db")
```

Defining tables:
```python
from trivela.orm import Table, Column, ForeignKey

class Author(Table):
    name = Column(str)
    age = Column(int)

class Book(Table):
    title = Column(str)
    published = Column(bool)
    author = ForeignKey(Author)
```

Creating tables:
```python
db.create(Author)
db.create(Book)
```

Creating an instance and inserting a row in database:
```python
david = Author(name='David', age=23)
db.save(david)
```

Fetching all rows from database:
```python
authors = db.all(Author)
```

Fetching a specific row by `Id`:
```python
author = db.get(Author, 100)

```

Saving an object with a foreign key reference:
```python
book = Book(title="Hello world", published=True, author=david)
db.save(book)

```

Fetching an object with a foreign key:
```python
print(db.get(Book, 100).author.name)
```

Updating an object:
```python
book.title = "World Hello"
db.update(book)
```

Deleting an object:
```python
db.delete(Book, id=book.id)
```