# SMDB Web Server
An easy to use, not secured web server, because I don't like the other options, and I like to create my own solutions most of the time.
## Table of content
| Section Name |
|:---------------------------:|
| [Usage](#usage) |
| [Get handler](#get-handler) |
| [Put Handler](#put-handler) |
| [Data](#data) |
## Usage
To start using this HTTP Server, import the `HTMLServer` class, and initialize it.
```python
from smdb_web_server import HTMLServer, UrlData
server = HTMLServer("127.0.0.1", 8080, title="Example server")
```
An `smdb_logger` can be used, if desired, but not neccesery.
To add a new url path, use the `add_url_rule` command.
```python
def index_handler(url_data: UrlData) -> str:
...
server.add_url_rule("/", index_handler)
```
This method will be called with a `GET` request by default. This can be set as an optional parameter called `protocol`. For now, only `GET` and `PUT` are supported.
Url handlers can be assigned with a decorator as well:
```python
@server.as_url_rule("/help")
def help_handler(url_data: UrlData) -> str:
...
```
To start the server, use either the `serve_forever` or the `serve_forever_threaded` function. The first will be a blocking call, the second will create a new thread.
```python
server.serve_forever_threaded(template_dictionary, static_dictionary, "Example Thread")
```
Both handlers can fail with [KnownError](#knownerror) exception, whitch will result in a user controlled return code and reason.
## GET handler
This handler can return any string, but it's usefull, if it returns an HTML file as string. This can be a hardcoded HTML code, or a static or dynamic file. For rendering HTML template files, the server has a helper function called `render_template_file`. This can render an HTML file from a pre setup dictionary.
```python
def index_handler(url_data: UrlData) -> str:
example_list = ["value1", "value2|False", "value3|True"]
return server.render_template("index", page_title="Example Title", example_selector=example_list, button_1="Button 1 name", button_2="Button 2 name")
```
If you need to just create a list to update an already rendered HTML page's selector, you can use it the following way:
```python
def update(url_data: UrlData):
return server.render_template_list("example_selector", ["value1|True", "value2|False", "value3|False"])
server.add_url_rule("/update", update)
```
This will result in the following list, if we use the `option` tag as shown in the [template_dictionary](#template-dictionary) in the [data](#data) paragraph:
```HTML
<option disabled></option>
<option value="value1" selected>value1</option>
<option value="value2">value2</option>
<option value="value3">value3</option>
```
This list will be sent as a `plaintext` response.
## Put Handler
This handler can return a simple string. The incoming data will be a bytearray of the body of the request.
```python
from smdb_web_server import Protocol
def put_handler(url_data: UrlData) -> str:
# Do stuff here.
# Either return with string, or fail with KnownError
...
server.add_url_rule("/put", put_handler, Protocol.Put)
```
## Data
### Template dictionary
- Keys: The "file name" without extention
- Value: The file's content, or a path in the following format: "PATH|{Relative path to file}"
This dictionary will be used to generate HTML response from the template. Theese templates can have replaceable values with the following format.
```HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ page_title }}</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<div class="container">
<h2>Example Header</h2>
<div class="grid-container">
<label for="ExampleSelector">Example Selector:</label>
<select id="ExampleSelector" class="fixed-width">
{{[ example_selector ]}}
</select>
<div class="button-group">
<button id="ExampleButton1">{{ button_1 }}</button>
<button id="ExampleButton2">{{ button_2 }}</button>
</div>
</div>
</div>
<script src="/static/script.js"></script>
</body>
</html>
```
In this page the `{{ page_title }}`, the `{{ button_1 }}` and the `{{ button_2 }}` will be replaced with one value, and the `{{[ ExampleSelector ]}}` will be generated using a list.
This dictionary should contain a key-value pair with the value being a repeateable value to fill the `{{[ ExampleSelector ]}}` place.
```python
selector_values = """<option value="{{VALUE}}"{{SELECTED}}>{{VALUE}}</option>"""
```
Here, the `{{VALUE}}` will be replaced by the list's content, and the `{{SELECTED}}` will be replaced by either the value `selected` or with an emty string, if the list's value is formatted in the following manner: `{value}|True`. If the value following the `|` character is not "True", it will be treated as if it was not present.
You can return a list by calling the `render_template_list` function by itself, or by rendering a full HTML page by calling `render_template`, with a list as an argument.
### Static dictionary
- Keys: The "file name" without extention
- Value: Either the file's content, or a path in the following format: "PATH|{Relative path to file}"
Static files will be sent automatically, if the correct URL is called. In the [Template Dictionary](#template-dictionary) example, the javascript and the css files are loaded from the path `/static/{file_name}`. This will result in the `{file_name}` file being served from the dictionary.
### KnownError
This error is used to send a usercontrolled response code to the requester. This exception can be used the following way:
```python
from smdb_web_server import KnownError
def fail(_):
raise KnownError("Reason", 405)
```
### Protocol
This is a simple enum class to use with `add_url_rule` to determine the protocol to be used
Values: `Get`, `Put`
### UrlData
This dataclass contains the following fields, either filled or containing `None`:
- fragment: `String` object (Data following the `#` in the URL)
- query: `Dictionary` with string keys and values (Data following the `?` in the URL). The key will be the part following the `?` or `&` characters, and the value will be the part after the `=` sign. If there is no value, `None` will be used as a value in the dictionary.
- data: `Bytes` object (Payload of the request, if available)
Raw data
{
"_id": null,
"home_page": "https://github.com/NightKey/smdb-server",
"name": "smdb-web-server",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": null,
"author": "Janth\u00f3 D\u00e1vid",
"author_email": "davidjantho@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/21/86/02fe6dc41544276027b02b238974c3de096dec43b74ffa3f6d9d8d1bf58a/smdb_web_server-0.3.3.tar.gz",
"platform": null,
"description": "# SMDB Web Server\r\nAn easy to use, not secured web server, because I don't like the other options, and I like to create my own solutions most of the time.\r\n\r\n## Table of content\r\n| Section Name |\r\n|:---------------------------:|\r\n| [Usage](#usage) |\r\n| [Get handler](#get-handler) |\r\n| [Put Handler](#put-handler) |\r\n| [Data](#data) |\r\n\r\n## Usage\r\n\r\nTo start using this HTTP Server, import the `HTMLServer` class, and initialize it.\r\n\r\n```python\r\nfrom smdb_web_server import HTMLServer, UrlData\r\nserver = HTMLServer(\"127.0.0.1\", 8080, title=\"Example server\")\r\n```\r\n\r\nAn `smdb_logger` can be used, if desired, but not neccesery.\r\n\r\nTo add a new url path, use the `add_url_rule` command.\r\n\r\n```python\r\ndef index_handler(url_data: UrlData) -> str:\r\n ...\r\n\r\nserver.add_url_rule(\"/\", index_handler)\r\n```\r\n\r\nThis method will be called with a `GET` request by default. This can be set as an optional parameter called `protocol`. For now, only `GET` and `PUT` are supported.\r\n\r\nUrl handlers can be assigned with a decorator as well:\r\n\r\n```python\r\n@server.as_url_rule(\"/help\")\r\ndef help_handler(url_data: UrlData) -> str:\r\n ...\r\n```\r\n\r\nTo start the server, use either the `serve_forever` or the `serve_forever_threaded` function. The first will be a blocking call, the second will create a new thread.\r\n\r\n```python\r\nserver.serve_forever_threaded(template_dictionary, static_dictionary, \"Example Thread\")\r\n```\r\n\r\nBoth handlers can fail with [KnownError](#knownerror) exception, whitch will result in a user controlled return code and reason.\r\n\r\n## GET handler\r\n\r\nThis handler can return any string, but it's usefull, if it returns an HTML file as string. This can be a hardcoded HTML code, or a static or dynamic file. For rendering HTML template files, the server has a helper function called `render_template_file`. This can render an HTML file from a pre setup dictionary.\r\n\r\n```python\r\ndef index_handler(url_data: UrlData) -> str:\r\n example_list = [\"value1\", \"value2|False\", \"value3|True\"]\r\n return server.render_template(\"index\", page_title=\"Example Title\", example_selector=example_list, button_1=\"Button 1 name\", button_2=\"Button 2 name\")\r\n```\r\n\r\nIf you need to just create a list to update an already rendered HTML page's selector, you can use it the following way:\r\n\r\n```python\r\ndef update(url_data: UrlData):\r\n return server.render_template_list(\"example_selector\", [\"value1|True\", \"value2|False\", \"value3|False\"])\r\n\r\nserver.add_url_rule(\"/update\", update)\r\n```\r\n\r\nThis will result in the following list, if we use the `option` tag as shown in the [template_dictionary](#template-dictionary) in the [data](#data) paragraph:\r\n\r\n```HTML\r\n<option disabled></option>\r\n<option value=\"value1\" selected>value1</option>\r\n<option value=\"value2\">value2</option>\r\n<option value=\"value3\">value3</option>\r\n```\r\n\r\nThis list will be sent as a `plaintext` response.\r\n\r\n## Put Handler\r\n\r\nThis handler can return a simple string. The incoming data will be a bytearray of the body of the request.\r\n```python\r\nfrom smdb_web_server import Protocol\r\n\r\ndef put_handler(url_data: UrlData) -> str:\r\n # Do stuff here.\r\n # Either return with string, or fail with KnownError\r\n ...\r\n\r\nserver.add_url_rule(\"/put\", put_handler, Protocol.Put)\r\n```\r\n\r\n## Data\r\n\r\n### Template dictionary\r\n - Keys: The \"file name\" without extention\r\n - Value: The file's content, or a path in the following format: \"PATH|{Relative path to file}\"\r\n\r\nThis dictionary will be used to generate HTML response from the template. Theese templates can have replaceable values with the following format.\r\n```HTML\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>{{ page_title }}</title>\r\n <link rel=\"stylesheet\" href=\"/static/style.css\">\r\n</head>\r\n<body>\r\n <div class=\"container\">\r\n <h2>Example Header</h2>\r\n <div class=\"grid-container\">\r\n <label for=\"ExampleSelector\">Example Selector:</label>\r\n <select id=\"ExampleSelector\" class=\"fixed-width\">\r\n {{[ example_selector ]}}\r\n </select>\r\n <div class=\"button-group\">\r\n <button id=\"ExampleButton1\">{{ button_1 }}</button>\r\n <button id=\"ExampleButton2\">{{ button_2 }}</button>\r\n </div>\r\n </div>\r\n </div>\r\n <script src=\"/static/script.js\"></script>\r\n</body>\r\n</html>\r\n```\r\n\r\nIn this page the `{{ page_title }}`, the `{{ button_1 }}` and the `{{ button_2 }}` will be replaced with one value, and the `{{[ ExampleSelector ]}}` will be generated using a list.\r\n\r\nThis dictionary should contain a key-value pair with the value being a repeateable value to fill the `{{[ ExampleSelector ]}}` place.\r\n\r\n```python\r\nselector_values = \"\"\"<option value=\"{{VALUE}}\"{{SELECTED}}>{{VALUE}}</option>\"\"\"\r\n```\r\n\r\nHere, the `{{VALUE}}` will be replaced by the list's content, and the `{{SELECTED}}` will be replaced by either the value `selected` or with an emty string, if the list's value is formatted in the following manner: `{value}|True`. If the value following the `|` character is not \"True\", it will be treated as if it was not present.\r\n\r\nYou can return a list by calling the `render_template_list` function by itself, or by rendering a full HTML page by calling `render_template`, with a list as an argument.\r\n\r\n### Static dictionary\r\n - Keys: The \"file name\" without extention\r\n - Value: Either the file's content, or a path in the following format: \"PATH|{Relative path to file}\"\r\n\r\nStatic files will be sent automatically, if the correct URL is called. In the [Template Dictionary](#template-dictionary) example, the javascript and the css files are loaded from the path `/static/{file_name}`. This will result in the `{file_name}` file being served from the dictionary.\r\n\r\n### KnownError\r\n\r\nThis error is used to send a usercontrolled response code to the requester. This exception can be used the following way:\r\n\r\n```python\r\nfrom smdb_web_server import KnownError\r\ndef fail(_):\r\n raise KnownError(\"Reason\", 405)\r\n```\r\n\r\n### Protocol\r\n\r\nThis is a simple enum class to use with `add_url_rule` to determine the protocol to be used\r\n\r\nValues: `Get`, `Put`\r\n\r\n### UrlData\r\n\r\nThis dataclass contains the following fields, either filled or containing `None`:\r\n\r\n - fragment: `String` object (Data following the `#` in the URL)\r\n - query: `Dictionary` with string keys and values (Data following the `?` in the URL). The key will be the part following the `?` or `&` characters, and the value will be the part after the `=` sign. If there is no value, `None` will be used as a value in the dictionary.\r\n - data: `Bytes` object (Payload of the request, if available)\r\n",
"bugtrack_url": null,
"license": null,
"summary": "A really basic, not so safe web server.",
"version": "0.3.3",
"project_urls": {
"Bug Tracker": "https://github.com/NightKey/smdb-server/issues",
"Homepage": "https://github.com/NightKey/smdb-server"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "403fae2b293519058d787467f0a9dd9e25f7d4ba629fb2890cc1098d45e17f26",
"md5": "08c93d4a6feb289ec0e5a8525756cb75",
"sha256": "aff45a327a6ddc7382da26d0bdff37bbc1182617bd36af13aeb4d24ed8cc0941"
},
"downloads": -1,
"filename": "smdb_web_server-0.3.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "08c93d4a6feb289ec0e5a8525756cb75",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 8266,
"upload_time": "2024-05-16T14:31:04",
"upload_time_iso_8601": "2024-05-16T14:31:04.811586Z",
"url": "https://files.pythonhosted.org/packages/40/3f/ae2b293519058d787467f0a9dd9e25f7d4ba629fb2890cc1098d45e17f26/smdb_web_server-0.3.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "218602fe6dc41544276027b02b238974c3de096dec43b74ffa3f6d9d8d1bf58a",
"md5": "a7bfd04e8134b1aedc54af8ce8315122",
"sha256": "18046630da134d354c90fd47e9b876e303ffc589d4fadda10d44d7ab56db8c5c"
},
"downloads": -1,
"filename": "smdb_web_server-0.3.3.tar.gz",
"has_sig": false,
"md5_digest": "a7bfd04e8134b1aedc54af8ce8315122",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 8192,
"upload_time": "2024-05-16T14:31:06",
"upload_time_iso_8601": "2024-05-16T14:31:06.108455Z",
"url": "https://files.pythonhosted.org/packages/21/86/02fe6dc41544276027b02b238974c3de096dec43b74ffa3f6d9d8d1bf58a/smdb_web_server-0.3.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-05-16 14:31:06",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "NightKey",
"github_project": "smdb-server",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "smdb-web-server"
}