WeefPy 2.0.4
Tiny Python web API framework
Requires Python: >=3.8

# WeefPy - Tiny Python web API framework

Tiny WSGI-Python framework designed mainly for REST API backends

## Installing WeefPy

Simply use pip for install this package
Installation:
```sh
$ pip install WeefPy # basic version
$ pip install WeefPy[orjson] # orjson version
$ pip install WeefPy[ujson] # ujson version
```

## Running development server
Before using development server install its dependencies
```sh
$ pip install uwsgi argparse python-daemon
```
Then you can run:
```sh
$ weef_server [weef server parameters]
```

#### Using
Change directory to project folder and run devserver.

```sh
$ weef_server --host 127.0.0.1 --port 8080 --app `file`:`callable`
```
Replace `file` with filename with your main function and `callable` with your function. <br>
App should run on [localhost:8080](http://localhost:8080/).

#### Command parameters
- `--config` should contain uwsgi ini configuration file
- `--host` should contain IP address to be server binded on
- `--port` should contain port to be server binded on
- `--app` should contain file and callable object separated by colon. (main.py:main)
- `--pythonpath` should contain your code directory for imports in your project
- `--daemon` starts server in deamon mode

### Bash syntax:
```sh
$ weef_server [--config CONFIG] [--host IP_ADDRESS] [--port PORT] [--app file:callable] [--pythonpath path] [--daemon]
```

You can create server configuration in uwsgi ini file. <br>
If you want to run python files without devserver add project directory to `PYTHONPATH`.

## Using WeefPy

### Initializing

```py
from WeefPy import WSGI

application = WSGI()

```
#### WSGI parameters:
- middleware - provide class extended from `Middleware` default class called before / in routed state / at end of every request (optional, default: None)
- content_type - this argument specifies the default content type of generated responses (optional, default: "application/json")
- charset - this argument specifies the default charset generated responses (optional, default: "UTF-8")

#### WSGI items:
- status_codes - dictionary of status codes (to see status_codes in WSGI parameters section)


###### Middleware example
```py
from WeefPy import WSGI, MiddlewareAbstract


# simple counting middleware example
class Middleware(MiddlewareAbstract):
	class Middleware:
	__slots__ = ()
	at_begin = 0
	at_routed = 0
	at_end = 0

	def begin(self, req, resp):
		self.at_begin += 1

	def routed(self, req, resp, route_args):
		self.at_begin -= 1
		self.at_routed += 1

	def end(self, req, resp, route_args):
		self.at_routed -= 1
		self.at_end += 1



application = WSGI(middleware=Middleware, content_type="text/html", charset="UTF-8")

```

### Routes

#### Route parameters
- endpoint - object should contain str or regex Pattern to match request path (mandatory)
- methods - list of HTTP methods to match request method - higher priority than method (optional, default: [])
- method - single HTTP method to match request method (optional, default: `GET`)
- *kwargs - other arguments - can be accessed by midlleware in states `routed` and `end`

#### Using
Route is used as a decorator callable object you want to use as router method.
Router method takes two mandatory arguments `Request` and `Response` (explained below in a separate section).
Router method can also take variables from router regex match (if used).

#### Examples

```py
import re
from WeefPy import Route


@Route("/endpoint", method="GET")  # simple route
def routed_method_1(request, response):  # simple route method
	return "Response from route 1" # response return without status code & mime type

# re package import needed
@Route(re.compile(r"/endpoint/(\d+)$"), methods=["GET", "POST"]) # regex route, with multiple methods
def routed_method_2(request, response, number):
	return "Response from route - urlnumber is: %s" % number, "200 OK", "text/html" # full response return

@Route("/endpoint3", methods=["GET", "POST"]) #simple route, with multiple methods
def routed_method_2(request, response):
	response.set("Response by set") # alternatively can be called reponse method set to set response

```

### Raise HTTP status

Raise HTTPStatus f with parameters (status, message)

```py
from WeefPy import Route, HTTPStatus

@Route("/raise_endpoint", methods=["POST"])
def routed_method_2(request, response):
	if not request.data:
		raise HTTPStatus("400 BAD REQUEST", "400 BAD REQUEST")
	return "data sent"
```

### Request & Response objects

Instances of these object are given to every function that is called with `@Route` decorator

```py
@Route("/endpoint", method="GET")
def endpoint(Request, Response):  # instances of Request and Response objects
	pass
```

#### Request items and methods
- host - host recieved message (ip, domain etc.) : read only
- method - request method (GET, POST etc.) : read only
- path - request path: read only
- query_string - request query_string
- data - request parsed data (json, -www-form-urlencoded, multipart/form-data) : read only
- content_type - request content type : read_only
- content_length - request content length
- cookie - `SimpleCookie` object instance with request cookies loaded
- storage - dict which used by for sharing data between middleware methods and / or routed method
- headers - HTTP headers : read only
- body - get response body : read only
- status - get response status : read only

#### Response  items and methods
- raw_response - `wsgi response` object
- encoding - response encoding; default: `UTF-8`
- headers - response headers
<br><br>
- set(body, status, content_type) - sets response (`body` (mandatory), `status` - by defaul is set to `200 OK`, `content_type` - if not provided is inherited from `WSGI object content_type`)
- redirect(location, status) - redirects response to (`location`, `status` if not providet is set to `302`)
- set_cookie(name, value, expires=None, maxAge=None, **kwargs) - adds cookie to response with obvious parameres, you can alwo add additional arguments (`kwargs`) such as `Domain`, `Path`, `Secure`, `HttpOnly`
- add_header(name, value) - adds header to response

## Example

Save this file as main.py
```py
from WeefPy import WSGI, Route

application = WSGI(content_type="text/html")


@Route("/endpoint", method="GET")
def endpoint(Request, Response):
	Response.add_header("X-header", "blahblah")  # set response header
	Response.set_cookie("cookie_from_server", "384")  # set reponse cookie
	return "Response BODY"
```

Now you should run weef_server
```sh
$ weef_server --host 127.0.0.1 --port 8080 --app main.py:application
```
App should run on [localhost:8080](http://localhost:8080/).<br>
http://localhost:8080/endpoint should now returns "Response BODY"