aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormg2023-04-25 20:52:45 +0200
committermg2023-04-25 20:52:45 +0200
commit13a3ab00761a7aa56780fd5d066e618da102e8c5 (patch)
tree96387fbf24d6252673d76e0d0aa13b5400eb1db1
parentef96c7167a37f320f8cfdb60dcef0c87184333d8 (diff)
add swagger (#1)v2
Co-authored-by: Michael Grote <michael.grote@posteo.de> Reviewed-on: https://git.mgrote.net/mg/python-api-server/pulls/1
-rw-r--r--README.md107
-rw-r--r--app.py88
-rw-r--r--docker-compose.yml18
-rw-r--r--requirements.txt1
4 files changed, 109 insertions, 105 deletions
diff --git a/README.md b/README.md
index 72f439b..3bd9894 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,6 @@
a small flask-application for storing and downloading stuff like small binaries
-
## Variables
- ``MAX_CONTENT_LENGTH``: maximal Filesize in MB; defaults to 5MB
@@ -11,94 +10,28 @@ a small flask-application for storing and downloading stuff like small binaries
## Example Docker-Compose
-see [docker-compose.yml](./docker-compose.yml)
-
-## API-Endpoints
-
-### /list
-
-#### input
-
-```bash
-curl -H "token: myuploadtoken" http://docker10.host.lan:5040/list | jq
-```
-
-#### output
-
-```bash
-{
- "files": [
- {
- "last_modified": "2023-04-13 11:43:51",
- "name": "file1",
- "size": 1034
- },
- {
- "last_modified": "2023-04-13 11:53:59",
- "name": "file2",
- "size": 5
- },
- {
- "last_modified": "2023-04-13 12:41:18",
- "name": "file3",
- "size": 3478
- }
- ]
-}
-```
-
-### /upload
-
-If a existing file has the same name as the newly uploaded file, it will be overwritten.
-
-#### input
-
-```bash
-curl -X POST -H "token: myuploadtoken" -F "file=@tests/file" http://docker10.host.lan:5040/upload | jq
-```
-
-#### output
+```yaml
+version: '3'
+services:
+ python-api-server:
+ container_name: httpd-api
+ image: quotengrote/python-api-server:v2
+ ports:
+ - "5040:5000"
+ volumes:
+ - uploads:/uploads
+ environment:
+ # FLASK_DEBUG: 1 # for debugging
+ # FLASK_APP: app # for debugging
+ MAX_CONTENT_LENGTH: 10
+ UPLOAD_DIRECTORY: /uploads
+ AUTH_TOKEN: myuploadtoken
-```bash
-{
- "success": "File 'file' successfully uploaded"
-}
-```
-
-### /download
-
-#### input
-
-```bash
-wget http://docker10.host.lan:5040/download/file
-```
-
-### /delete
-
-#### input
-
-```bash
-curl -X DELETE -H "token: myuploadtoken" http://docker10.host.lan:5040/delete/file | jq
-```
-
-#### output
-
-```bash
-{
- "success": "File 'file' successfully deleted"
-}
-```
+volumes:
+ uploads:
-### /health
-
-#### input
-
-```bash
-curl http://docker10.host.lan:5040/health
```
-#### output
+## API-Endpoints
-```bash
-OK
-```
+- see [Flasgger](https://github.com/flasgger/flasgger): ``http://<host>:5040/apidocs/``
diff --git a/app.py b/app.py
index cb1cf9d..dd49463 100644
--- a/app.py
+++ b/app.py
@@ -3,8 +3,10 @@ import re
import uuid
from flask import Flask, request, jsonify, send_from_directory
import datetime
+from flasgger import Swagger, swag_from
app = Flask(__name__)
+swagger = Swagger(app)
app.config['UPLOAD_DIRECTORY'] = os.environ.get('UPLOAD_DIRECTORY', '/uploads')
app.config['MAX_CONTENT_LENGTH'] = int(os.environ.get('MAX_CONTENT_LENGTH', '5')) * 1024 * 1024 # in MB
@@ -17,10 +19,41 @@ def is_valid_filename(filename):
@app.route('/health', methods=['GET'])
def health_check():
+ """
+ Endpoint for health check.
+ ---
+ responses:
+ 200:
+ description: OK
+ """
return 'OK'
@app.route('/upload', methods=['POST'])
def upload_file():
+ """
+ Endpoint for uploading files.
+ Filename can only contain alphanumeric characters, hyphens, underscores, and periods.
+ If the filename is the same as an existing file, this file will be overwritten.
+ ---
+ parameters:
+ - name: file
+ in: formData
+ type: file
+ required: true
+ description: The file to upload.
+ - name: token
+ in: header
+ type: string
+ required: true
+ description: Authentication token.
+ responses:
+ 200:
+ description: File uploaded successfully.
+ 400:
+ description: Bad request.
+ 401:
+ description: Unauthorized.
+ """
if 'file' not in request.files:
return jsonify({'error': 'No file part in the request'}), 400
@@ -43,6 +76,21 @@ def upload_file():
@app.route('/download/<filename>', methods=['GET'])
def download_file(filename):
+ """
+ Endpoint for downloading files.
+ ---
+ parameters:
+ - name: filename
+ in: path
+ type: string
+ required: true
+ description: The name of the file to download.
+ responses:
+ 200:
+ description: File downloaded successfully.
+ 404:
+ description: File not found.
+ """
try:
return send_from_directory(app.config['UPLOAD_DIRECTORY'], filename)
except FileNotFoundError:
@@ -50,6 +98,28 @@ def download_file(filename):
@app.route('/delete/<filename>', methods=['DELETE'])
def delete_file(filename):
+ """
+ Endpoint for deleting files.
+ ---
+ parameters:
+ - name: filename
+ in: path
+ type: string
+ required: true
+ description: The name of the file to delete.
+ - name: token
+ in: header
+ type: string
+ required: true
+ description: Authentication token.
+ responses:
+ 200:
+ description: File deleted successfully.
+ 401:
+ description: Unauthorized.
+ 404:
+ description: File not found.
+ """
if 'token' not in request.headers:
return jsonify({'error': 'No token supplied'}), 401
@@ -63,8 +133,26 @@ def delete_file(filename):
os.remove(file_path)
return jsonify({'success': 'File \'{}\' successfully deleted'.format(filename)})
+
@app.route('/list', methods=['GET'])
def list_files():
+ """
+ Endpoint for listing files.
+ ---
+ parameters:
+ - name: token
+ in: header
+ type: string
+ required: true
+ description: Authentication token.
+ responses:
+ 200:
+ description: Listed files successfully.
+ 400:
+ description: Bad request.
+ 401:
+ description: Unauthorized.
+ """
if 'token' not in request.headers:
return jsonify({'error': 'No token supplied'}), 401
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index 52b1267..0000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-version: '3'
-services:
- python-api-server:
- container_name: httpd-api
- image: quotengrote/python-api-server:latest
- ports:
- - "5040:5000"
- volumes:
- - uploads:/uploads
- environment:
- # FLASK_DEBUG: 1 # for debugging
- # FLASK_APP: app # for debugging
- MAX_CONTENT_LENGTH: 10
- UPLOAD_DIRECTORY: /uploads
- AUTH_TOKEN: myuploadtoken
-
-volumes:
- uploads:
diff --git a/requirements.txt b/requirements.txt
index c23a02a..302e5d4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,3 +2,4 @@ Flask==2.0.1
Flask-Cors==3.0.10
gunicorn
requests
+flasgger