https://github.com/moustikitos/micro-server
Pure python json server library
https://github.com/moustikitos/micro-server
framework python web wsgi-server
Last synced: 3 months ago
JSON representation
Pure python json server library
- Host: GitHub
- URL: https://github.com/moustikitos/micro-server
- Owner: Moustikitos
- License: mit
- Created: 2020-04-22T09:59:16.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2025-02-20T11:38:59.000Z (4 months ago)
- Last Synced: 2025-04-13T05:05:28.623Z (3 months ago)
- Topics: framework, python, web, wsgi-server
- Language: Python
- Homepage:
- Size: 985 KB
- Stars: 4
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# `usrv`: the lightest python web framework
[](https://raw.githubusercontent.com/Moustikitos/micro-server/master/LICENSE)
Package (`usrv`) is a pure python micro server implementation. It allows python function bindings for all HTTP methods. HTTP body can be encrypted on demand using secp256k1 keypairs.
## Install
### Developpment version
```bash
$ python -m pip install git+https://github.com/Moustikitos/micro-server#egg=usrv
```### last version (0.4.2)
```bash
$ python -m pip install usrv
```## `usrv.route`
Bind python code to any HTTP requests easily using decorator syntax.
`route` module can be used in standalone mode outside of `usrv` package.## `usrv.app`
Run a low footprint python server or [PEP#3333 WSGI server](https://www.python.org/dev/peps/pep-3333).
```python
import waitress # wsgi server for windows
from usrv import app, route@route.bind("/index")
def index(**kw):
return 200, "Index page", kwwaitress.serve(app.uApp(), threads=2)
```## Fast and simple
Let's create a server with `/test` endpoint in a python module named `test.py`:
```python
from usrv import route, app@route.bind("/test")
def do_test(a, b):
# write some code and return something
return 200, a, bdef launchApp():
route.run(host="127.0.0.1", port=5000, loglevel=20)
```**Bound functions have to return a tuple with a valid HTTP status code as first item**.
Server can be run from python interpreter:```python
>>> import test
>>> test.launchApp()
INFO:usrv.srv:listening on 127.0.0.1:5000
CTRL+C to stop...
```Now going to `http://127.0.0.1:5000/test` with any browser gives:
```json
[null, null]
```## Extracting values from url query
`[null, null]` above are the returned values `a` and `b` from `do_test` function. Values can be extracted from query string. Let's type `http://127.0.0.1:5000/test?b=12&a=Paris` in the address bar:
```json
["Paris", "12"]
```Returned value from query are `str` only. Unexpected values are ignored but there is a [convenient way to catch them](#catching-unexpected-values).
## Extracting values from url path
Values can also be extracted from url path with or without a typing precision.
```python
@route.bind("//")
def do_test(a, b):
# write some code and return something
return 200, a, b
```This binding creates multiple endpoint possibilities. Let's try `http://127.0.0.1:5000/5/test`:
```json
["test", 5]
```Values from url can be overrided by thoses from query... `http://127.0.0.1:5000/5/test?a=2&b=6`:
```json
["2", "6"]
```> It can only be overrided with `str` type values.
## Catching unexpected values
Using varargs or/and keywordargs is a convenient way to catch unexpected values from url query and HTTP context. HTTP Context is defined an headers and data (HTTP requests with body).
When HTTP context is catched by `*args`, unexpected values from query string are appended next.
Url used for this chapter `http://127.0.0.1:5000/test?b=12&a=Paris&unexpected=there`.
### Variable args (`*args`)
```python
@route.bind("/test")
def do_test(a, b, *args):
# write some code and return something
# args is a tuple
return 200, a, b, args
```> With `*args` method, HTTP headers and data will be postionned at the end of `json` response
```json
[
"Paris",
"12",
"there",
"GET",
{
"host": "127.0.0.1:5000",
"connection": "keep-alive",
"sec-ch-ua": "\"Brave\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
"sec-gpc": "1",
"accept-language": "fr-FR,fr",
"sec-fetch-site": "none",
"sec-fetch-mode": "navigate",
"sec-fetch-user": "?1",
"sec-fetch-dest": "document",
"accept-encoding": "gzip, deflate, br, zstd"
},
null
]
```### Keyword args (`**kwargs`)
```python
@route.bind("/test")
def do_test(a, b, **kwargs):
# write some code and return something
# kwargs is a dict
return 200, a, b, kwargs
```> using `**kwargs` is the recommended way to retrieve unexpected values by names. Unexpected mapping is positionned at the end of `json` response.
```json
[
"Paris",
"12",
{
"unexpected": "there",
"method": "GET",
"headers": {
"host": "127.0.0.1:5000",
"connection": "keep-alive",
"sec-ch-ua": "\"Brave\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
"sec-gpc": "1",
"accept-language": "fr-FR,fr",
"sec-fetch-site": "none",
"sec-fetch-mode": "navigate",
"sec-fetch-user": "?1",
"sec-fetch-dest": "document",
"accept-encoding": "gzip, deflate, br, zstd"
},
"data": null,
}
]
```## Command line
WSGI server can be launched from command line.
```bash
$ python wsgi_srv.py -h
Usage: wsgi_srv.py [options] BINDINGS...Options:
--version show program's version number and exit
-h, --help show this help message and exit
-t THREADS, --threads=THREADS
set thread number [default: 2]
-l LOGLEVEL, --log-level=LOGLEVEL
set log level from 1 to 100 [default: 20]
-i HOST, --ip=HOST ip to run from [default: 127.0.0.1]
-p PORT, --port=PORT port to use [default: 5000]
````BINDINGS` is a space-separated-list of python module names (ie no `*.py` extention) containing boud python functions. Modules containing bound functions have to be in one of `sys.path` folder. Specific folder can be added using `wsgi_srv.path` file.
## Changes
### 0.4.1
- [x] major changes and improvement, no backward compatibility with 0.3.0
### 0.4.2
- [x] improved `route.uHTTPRequstHandler` response
- [x] added body encryption/decryption based on `secp256k1` and `AES`
- [x] added multipart/form-data body management to req module
- [x] added custom client/server identification
- [x] added secured secret dump and load
- [x] added replay attack mitigation
- [x] added endpoint builder
- [x] added [pinata](https://pinata.cloud) plugin
- [x] added [binance](https://binance.com) plugin### 0.4.3 (dev)
- [x] replaced ECDSA signatures with SCHNORR signatures
- [x] added C implementation of SCHNORR signatures
- [x] nonce flushing launch on startup## Support this project
[](https://liberapay.com/Toons/donate)
[](https://paypal.me/toons)