mirror of
https://github.com/bpetschowitsch/weba.git
synced 2026-06-01 16:39:42 +00:00
Create 11_webservice.md
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
# Webservice
|
||||
|
||||
## Webservice itself
|
||||
We use flask as application server (python based).
|
||||
Check if flask is installed/otherwise install it...
|
||||
|
||||
```bash
|
||||
sudo apt list python3 python3-venv --installed
|
||||
```
|
||||
```bash
|
||||
sudo apt install python3 python3-venv -y
|
||||
```
|
||||
|
||||
create a folder for the source-code & python dependencies:
|
||||
|
||||
```bash
|
||||
sudo mkdir /opt/webservice
|
||||
sudo chown tux:tux /opt/webservice
|
||||
```
|
||||
|
||||
install python dependencies and webservice:
|
||||
|
||||
```bash
|
||||
cd /opt/webservice
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install flask flask-restx gunicorn
|
||||
deactivate
|
||||
|
||||
vi webservice.py
|
||||
```
|
||||
|
||||
and paste following code:
|
||||
|
||||
```python
|
||||
from flask import Flask
|
||||
from flask_restx import Api, Resource
|
||||
|
||||
app = Flask(__name__)
|
||||
api = Api(app)
|
||||
|
||||
names_list = ["Alice", "Bob", "Charlie"]
|
||||
|
||||
@api.route('/names')
|
||||
class AddressList(Resource):
|
||||
|
||||
def get(self):
|
||||
return names_list
|
||||
|
||||
def post(self):
|
||||
data = api.payload
|
||||
if "name" in data:
|
||||
names_list.append(data["name"])
|
||||
return {"status": "success"}, 201
|
||||
api.abort(400)
|
||||
|
||||
def delete(self):
|
||||
names_list.clear()
|
||||
return {"status": "Liste geleert"}, 200
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||
```
|
||||
|
||||
test the webservice:
|
||||
|
||||
```bash
|
||||
/opt/webservice/venv/bin/python3 webservice.py
|
||||
```
|
||||
|
||||
Verify the webservice using Postman!
|
||||
URL: `http://<server-ip-address>:5000/names`
|
||||
|
||||
## Reverse-Proxy
|
||||
|
||||
Stop the webservice simply by pressing `Ctrl + C`, or by `kill <pid>`.
|
||||
change the binding of flask to localhost only by modifing the last line of the webservice source-code:
|
||||
|
||||
```python
|
||||
if __name__ == '__main__':
|
||||
app.run(host='127.0.0.1', port=5000, debug=True)
|
||||
```
|
||||
|
||||
**Note:** The webservice is no longer accessible from outside the host.
|
||||
|
||||
Make the webservice available through nginx.
|
||||
|
||||
```bash
|
||||
sudo vi /etc/nginx/sites-available/*site-name*
|
||||
```
|
||||
|
||||
add to the server section:
|
||||
|
||||
```nginx
|
||||
# API Queries are forwarded to Flask
|
||||
location /api/names {
|
||||
proxy_pass http://127.0.0.1:5000/names;
|
||||
}
|
||||
```
|
||||
|
||||
reload nginx, start the webservice:
|
||||
|
||||
```bash
|
||||
sudo systemctl reload nginx
|
||||
/opt/webservice/venv/bin/python3 webservice.py
|
||||
```
|
||||
|
||||
Verify the webservice using Postman!
|
||||
|
||||
URL: `http://*domain-name*/api/names`
|
||||
|
||||
The previous URL should **NOT** work anylonger: `http://<server-ip-address>:5000/names`
|
||||
|
||||
To start the webservice "production ready", we have a use a wsgi server like gunicorn (which we installed initially via pip):
|
||||
|
||||
```bash
|
||||
/opt/webservice/venv/bin/gunicorn -w 1 -b 127.0.0.1:5000 webservice:app
|
||||
```
|
||||
|
||||
## API Documentation Example
|
||||
|
||||
|
||||
|
||||
| Method | Ressource (Path) | Input (Body) | Datatype (In) | Possible Values | Output (JSON) | Datatype (Out) | Description |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| **GET** | `/names` | *n/a* | - | - | `["Alice", "Bob", ...]` | `Array<String>` | returns the complete list of names |
|
||||
| **POST** | `/names` | `{"name": "..."}` | `String` | `*` | `{"status": "success"}` | `String` | adds a new name to the list |
|
||||
| **DELETE** | `/names` | *n/a* | - | - | `{"status": "Liste geleert"}` | `String` | clears the complete list |
|
||||
|
||||
|
||||
## Webapp -> Frontend
|
||||
|
||||
A simple frontend for the webservice. Create a html document (e.g. `webapp2.html`) with the content:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Demo: Addressbook</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>Einfaches Adressbuch</h2>
|
||||
|
||||
<input type="text" id="nameAdd" name="name" placeholder="Name eingeben..." required>
|
||||
<button onclick="addName()">Speichern</button>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>Einträge:</h3>
|
||||
<div id="nameList"></div>
|
||||
|
||||
<p><small><a id="deleteLink" href="#" onclick="deleteAll();return false;">Liste leeren</a></small></p>
|
||||
|
||||
<script>
|
||||
|
||||
const API_URL = '/api/names';
|
||||
|
||||
async function loadNames() {
|
||||
try {
|
||||
const response = await fetch(API_URL);
|
||||
const names = await response.json();
|
||||
const list = document.getElementById('nameList');
|
||||
list.innerHTML = names.map(n => `Benutzer: ${n}<br>`).join('');
|
||||
} catch (e) {
|
||||
console.error("Backend nicht erreichbar", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function addName() {
|
||||
const val = document.getElementById('nameAdd').value;
|
||||
if(!val) return;
|
||||
|
||||
await fetch(API_URL, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ "name": val })
|
||||
});
|
||||
document.getElementById('nameList').value = '';
|
||||
loadNames();
|
||||
}
|
||||
|
||||
async function deleteAll() {
|
||||
await fetch(API_URL, { method: 'DELETE' });
|
||||
loadNames();
|
||||
}
|
||||
|
||||
loadNames();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
Reference in New Issue
Block a user