From f259aa3993c78470cfde44cd67c40f221037ba36 Mon Sep 17 00:00:00 2001 From: Thastertyn Date: Wed, 13 Mar 2024 13:43:34 +0100 Subject: [PATCH] Work on swag documentation --- app/__init__.py | 6 ++--- app/api/routes/cart_routes.py | 2 +- app/api/routes/main_routes.py | 7 +++-- app/api/routes/product_routes.py | 2 +- app/api/routes/user_routes.py | 5 ++++ app/doc/{cart.py => cart_swag.py} | 26 ++++++++---------- app/doc/main_swag.py | 18 +++++++++++++ app/doc/product.py | 23 ---------------- app/doc/product_swag.py | 21 +++++++++++++++ app/doc/{main.py => root_swag.py} | 8 +++--- app/doc/user.py | 0 app/doc/user_swag.py | 45 +++++++++++++++++++++++++++++++ app/services/cart_service.py | 7 ++--- 13 files changed, 115 insertions(+), 55 deletions(-) rename app/doc/{cart.py => cart_swag.py} (75%) create mode 100644 app/doc/main_swag.py delete mode 100644 app/doc/product.py create mode 100644 app/doc/product_swag.py rename app/doc/{main.py => root_swag.py} (77%) delete mode 100644 app/doc/user.py create mode 100644 app/doc/user_swag.py diff --git a/app/__init__.py b/app/__init__.py index 2cf5aa8..c3ef147 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -2,13 +2,13 @@ from flask import Flask from flask_jwt_extended import JWTManager from flask_mail import Mail from flasgger import Swagger -from flask_cors import CORS + +from app.doc.main_swag import main_swagger app = Flask(__name__) jwt_manager = JWTManager(app) mail = Mail(app) -swag = Swagger(app) -cors = CORS(app) +swag = Swagger(app, template=main_swagger) def create_app(): from app.api import bp, bp_errors, bp_product, bp_user, bp_cart diff --git a/app/api/routes/cart_routes.py b/app/api/routes/cart_routes.py index 1f8c626..8625442 100644 --- a/app/api/routes/cart_routes.py +++ b/app/api/routes/cart_routes.py @@ -1,7 +1,7 @@ from flask import jsonify, abort, request from flask_jwt_extended import jwt_required, get_jwt_identity -from app.doc.cart import show_cart_swagger, add_to_cart_swagger +from app.doc.cart_swag import show_cart_swagger, add_to_cart_swagger from flasgger import swag_from diff --git a/app/api/routes/main_routes.py b/app/api/routes/main_routes.py index 0ff4e9c..f891e61 100644 --- a/app/api/routes/main_routes.py +++ b/app/api/routes/main_routes.py @@ -1,12 +1,11 @@ from flask import jsonify, abort - -from app.doc.main import main_swagger - from flasgger import swag_from +from app.doc.root_swag import root_swagger + from app.api import bp @bp.route('/') -@swag_from(main_swagger) +@swag_from(root_swagger) def hello(): return jsonify({'message': 'Hello, Flask!'}) \ No newline at end of file diff --git a/app/api/routes/product_routes.py b/app/api/routes/product_routes.py index ccbaa8e..086b0aa 100644 --- a/app/api/routes/product_routes.py +++ b/app/api/routes/product_routes.py @@ -1,7 +1,7 @@ from flask import jsonify, abort, request from flask_jwt_extended import jwt_required, get_jwt_identity -from app.doc.product import get_products_swagger +from app.doc.product_swag import get_products_swagger from flasgger import swag_from diff --git a/app/api/routes/user_routes.py b/app/api/routes/user_routes.py index ea14178..ff9654c 100644 --- a/app/api/routes/user_routes.py +++ b/app/api/routes/user_routes.py @@ -2,6 +2,10 @@ from app.api import bp_user from flask_jwt_extended import jwt_required, get_jwt_identity, get_jwt from flask import request, abort +from flasgger import swag_from + +from app.doc.user_swag import login_swagger + from app.services.user_service import UserService @bp_user.route('/register', methods=['POST']) @@ -19,6 +23,7 @@ def register(): return result, status_code @bp_user.route('/login', methods=['POST']) +@swag_from(login_swagger) def login(): username = request.json.get('username') password = request.json.get('password') diff --git a/app/doc/cart.py b/app/doc/cart_swag.py similarity index 75% rename from app/doc/cart.py rename to app/doc/cart_swag.py index 073451c..e4e104e 100644 --- a/app/doc/cart.py +++ b/app/doc/cart_swag.py @@ -1,13 +1,8 @@ show_cart_swagger = { "tags": ["Cart"], - "parameters": + "security": [ - { - "name": "Authorization", - "in": "header", - "type": "string", - "required": True - } + {"JWT": []} ], "responses": { @@ -45,24 +40,25 @@ show_cart_swagger = { add_to_cart_swagger ={ "tags": ["Cart"], + "security": + [ + {"JWT": []} + ], "parameters": [ - { - "name": "Authorization", - "in": "header", - "type": "string", - "required": True - }, { "name": "product_id", + "description": "ID of product to add to cart.", "in": "path", "type": "int", - "required": True }, { "name": "count", + "description": "Count of the products. If not provided, defaults to 1", "in": "query", "type": "int", + "default": 1, + "minimum": 1, "required": False } ], @@ -74,7 +70,7 @@ add_to_cart_swagger ={ }, "400": { - "description": "Incorrect usage. For example id of product not found or product count < 1" + "description": "Causes:\n- Count is < 1" } } } diff --git a/app/doc/main_swag.py b/app/doc/main_swag.py new file mode 100644 index 0000000..652bb22 --- /dev/null +++ b/app/doc/main_swag.py @@ -0,0 +1,18 @@ +main_swagger = { + "info": { + "title": "Shop API", + "version": "0.1", + "description": "Simple shop API using flask and co.\nFeatures include:\n- Not working\n- Successful registration of users\n- Adding items to cart\n- I don't know", + }, + "host": "localhost:1236", + "schemes": "http", + "securityDefinitions": { + "JWT": { + "type": "apiKey", + "scheme": "bearer", + "name": "Authorization", + "in": "header", + "description": "JWT Authorization header using the Bearer scheme.\n*Make sure to prefix the token with **Bearer**!*" + } + } +} \ No newline at end of file diff --git a/app/doc/product.py b/app/doc/product.py deleted file mode 100644 index fe8b8d7..0000000 --- a/app/doc/product.py +++ /dev/null @@ -1,23 +0,0 @@ -get_products_swagger = { - "paths": { - "/get": { - "get": { - "summary": "Get products", - "responses": { - "200": { - "description": "Successfully retrieved products", - "schema": { - "type": "object", - "properties": { - "products": {"type": "array", "items": {"type": "object", "properties": {"id": {"type": "int"}, "name": {"type": "string"}, "price": {"type": "float"}}}} - } - } - }, - "400": { - "description": "Bad request" - } - } - } - } - } -} \ No newline at end of file diff --git a/app/doc/product_swag.py b/app/doc/product_swag.py new file mode 100644 index 0000000..b570d58 --- /dev/null +++ b/app/doc/product_swag.py @@ -0,0 +1,21 @@ +get_products_swagger = { + "methods": ["GET"], + "tags": ["Products"], + "parameters": [ + + ], + "responses": + { + "200": + { + "description": "Get a page of products", + "schema": + { + "type": "object", + "properties": { + "message": {"type": "string", "example": "Hello, Flask!"} + } + } + } + } +} \ No newline at end of file diff --git a/app/doc/main.py b/app/doc/root_swag.py similarity index 77% rename from app/doc/main.py rename to app/doc/root_swag.py index 7a91f5e..c8b803b 100644 --- a/app/doc/main.py +++ b/app/doc/root_swag.py @@ -1,8 +1,5 @@ -main_swagger = { +root_swagger = { "methods": ["GET"], - "parameters": [ - - ], "responses": { "200": @@ -11,7 +8,8 @@ main_swagger = { "schema": { "type": "object", - "properties": { + "properties": + { "message": {"type": "string", "example": "Hello, Flask!"} } } diff --git a/app/doc/user.py b/app/doc/user.py deleted file mode 100644 index e69de29..0000000 diff --git a/app/doc/user_swag.py b/app/doc/user_swag.py new file mode 100644 index 0000000..f6e558a --- /dev/null +++ b/app/doc/user_swag.py @@ -0,0 +1,45 @@ +login_swagger = { + "methods": ["POST"], + "tags": ["User"], + "description": "Logs in using username and password and returns a JWT token for further authorization of requests.\n**The token is valid for 1 hour**", + "parameters": + [ + { + "in": "body", + "name": "body", + "description": "Username and password payload", + "required": True, + "schema": + { + "type": "object", + "properties": + { + "username": {"type": "string", "example": "mycoolusername"}, + "password": {"type": "string", "example": "MyStrongPassword123"} + } + } + } + ], + "responses": + { + "200": + { + "description": "Returns a fresh token", + "schema": + { + "type": "object", + "properties": { + "token": {"type": "string", "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxMDMyMjkyOCwianRpIjoiZDFhYzQxZDktZjA4NC00MmYzLThlMWUtZWFmZjJiNGU1MDAyIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6MjMwMDEsIm5iZiI6MTcxMDMyMjkyOCwiZXhwIjoxNzEwMzI2NTI4fQ.SW7LAi1j5vDOEIvzeN-sy0eHPP9PFJFkXYY029O35w0"} + } + } + }, + "400": + { + "description": "Possible causes:\n- Missing username or password from request.\n- Nonexistent username" + }, + "401": + { + "description": "Password is incorrect" + } + } +} \ No newline at end of file diff --git a/app/services/cart_service.py b/app/services/cart_service.py index 834353b..071c174 100644 --- a/app/services/cart_service.py +++ b/app/services/cart_service.py @@ -23,17 +23,18 @@ class CartService: cursor.execute("select count from cart_item where cart_id = %s and product_id = %s", (user_id, product_id)) result = cursor.fetchone() - if cursor.rowcount != 0: + if cursor.rowcount == 1: cursor.execute("update cart_item set count = count + %s where cart_id = %s and product_id = %s", (count, user_id, product_id)) else: cursor.execute("insert into cart_item(cart_id, product_id, count) values (%s, %s, %s)", (user_id, product_id, count)) db_connection.commit() - return {"Success": "Successfully added to cart"}, 200 except Error as e: - return {"Failed": f"Failed to add item to cart. Reason: {e}"}, 400 + return {"Failed": f"Failed to add item to cart. Reason: {e}"}, 500 + + return {"Success": "Successfully added to cart"}, 200 @staticmethod def update_count(user_id: str, product_id: int, count: int) -> Tuple[Union[dict, str], int]: