Skip to content

Commit bdda2f4

Browse files
committed
Feature: added Swagger UI support with OpenAPI spec 3.0, removing Flask_restx - Issue ##23
1 parent eac3eba commit bdda2f4

File tree

6 files changed

+201
-35
lines changed

6 files changed

+201
-35
lines changed

LogAggregator.py

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88
from pathlib import Path
99
from dotenv import load_dotenv
1010
from flask import Flask
11-
from flask_restx import Api
1211
from src.Logger.Logger import Logger
1312
from src.database import DB as db
1413
from src.auth import auth_bp, LogJWTManager as jwt
1514
from src.FileTransferManager.FileUploader import FileUploader
1615
from src.ConfigManager.ConfigManager import ConfigManager
1716
from src.FileTransferManager.ElasticConnector import ElasticConnector
1817
from src.blueprints import LogBlueprint
19-
from src.blueprints.docs import LogDoc
20-
from src.blueprints.docs.auth_doc import api as auth_namespace
18+
from src.docs.py.docs import doc_app
19+
#from src.blueprints.docs import LogDoc
20+
#from src.blueprints.docs.auth_doc import api as auth_namespace
2121

2222

2323
class LogAggregator:
@@ -54,29 +54,8 @@ def __init__(self,
5454
self.app.register_blueprint(log_bp,url_prefix='/')
5555
# register the blueprints for authentication: every authentication related resource needs to be prefixed with /auth
5656
self.app.register_blueprint(auth_bp,url_prefix='/auth')
57-
#Swagger UI setup with RESTX API:
58-
authentication = {
59-
'basic': {
60-
'type': 'basic',
61-
'scheme': 'basic',
62-
'in': 'header'},
63-
'jwt' : {
64-
'type': "oauth2",
65-
'scheme': 'bearer',
66-
'in': "header"
67-
}
68-
}
69-
restx_api = Api(app=self.app,
70-
version="1.0",
71-
title="LogAggregator API",
72-
description="LogAggregator API documentation",
73-
doc="/docs",
74-
authorizations=authentication)
75-
LogDoc(self.__log)
76-
log_namespace = LogDoc.get_api()
77-
restx_api.add_namespace(log_namespace, path="/log")
78-
restx_api.add_namespace(auth_namespace, path="/auth")
79-
57+
# Swagger UI implementation in a separate blueprint
58+
self.app.register_blueprint(doc_app, url_prefix='/api')
8059
except FileNotFoundError as exc:
8160
message = inspect.cleandoc("""Missing config.json file. Please provide a valid file when starting the app.
8261
If this app was started using Docker, please ensure that your Docker run has a -v volume binding that maps the config.json file

main.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,4 @@
66

77
from LogAggregator import LogAggregator
88

9-
app = LogAggregator().app
10-
app.run()
9+
app = LogAggregator().app

src/auth/Auth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def login():
2121

2222
return AuthService.login()
2323

24-
@auth_bp.post("/user/password")
24+
@auth_bp.put("/user/password")
2525
def change_password():
2626
"""
2727
Endpoint to allow chaning the password of an user. Only users with admin privileges can perform this acction
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
openapi: 3.0.0
2+
info:
3+
version: 1.0.0
4+
title: LogAggregator API
5+
description: A microservices based approach for log parsing, indexing and analysis.
6+
security:
7+
- bearerHttpAuthentication : []
8+
9+
paths:
10+
/auth/login:
11+
get:
12+
tags:
13+
- User
14+
description: Logs the user in the system
15+
security:
16+
- basicHttpAuthentication: []
17+
18+
responses:
19+
'200':
20+
description: User logged in successfully
21+
content:
22+
application/json:
23+
schema:
24+
type: object
25+
properties:
26+
message:
27+
type: string
28+
token:
29+
type: object
30+
properties:
31+
access:
32+
type: string
33+
refresh:
34+
type: string
35+
example: { "message": "Logged in", "token": { "access": "a valid access token", "refresh": "Its corresponding token" } }
36+
'400':
37+
description: "Bad request - invalid username or password"
38+
content:
39+
application/json:
40+
schema:
41+
type: string
42+
/auth/register:
43+
post:
44+
tags:
45+
- User
46+
description: Registers a new user in the system. Requires admin access.
47+
security:
48+
- bearerHttpAuthentication: []
49+
requestBody:
50+
content:
51+
application/json:
52+
schema:
53+
$ref: '#/components/schemas/User'
54+
55+
responses:
56+
'201':
57+
description: User created successfully
58+
content:
59+
application/json:
60+
schema:
61+
type: object
62+
properties:
63+
message:
64+
type: string
65+
example: { "message": "user created", "username": "wilsonphilips" }
66+
'400':
67+
description: "Bad request - Invalid parameters in request body"
68+
content:
69+
application/json:
70+
schema:
71+
type: object
72+
example: { "message": Illegal argument in your request. }
73+
'401':
74+
description: "Unauthorized - Current user does not have the necessary permissions to create a new user"
75+
content:
76+
application/json:
77+
schema:
78+
type: string
79+
example: { "message": "missing authorization for requested resource" }
80+
'409':
81+
description: Conflict - User already exists
82+
content:
83+
application/json:
84+
schema:
85+
type: string
86+
example: { "message": "User already exists"}
87+
/auth/user:
88+
delete:
89+
tags:
90+
- User
91+
description: Deletes a user from the system. requires admin access
92+
security:
93+
- bearerHttpAuthentication: []
94+
requestBody:
95+
content:
96+
application/json:
97+
schema:
98+
type: object
99+
properties:
100+
username:
101+
type: string
102+
responses:
103+
'200':
104+
description: User deleted successfully
105+
content:
106+
application/json:
107+
schema:
108+
type: object
109+
properties:
110+
message:
111+
type: string
112+
example: { "message": "user deleted"}
113+
'400':
114+
description: "Bad request"
115+
content:
116+
application/json:
117+
schema:
118+
type: object
119+
example: { "message": Illegal argument in your request. }
120+
121+
'401':
122+
description: "Unauthorized - missing authorization for requested resource"
123+
content:
124+
application/json:
125+
schema:
126+
type: object
127+
example: { "message": Missing authorization for requested resource }
128+
129+
/log:
130+
post:
131+
tags:
132+
- log
133+
security:
134+
- bearerHttpAuthentication: []
135+
requestBody:
136+
description: The logged message is expected to be of type as text/plain
137+
content:
138+
text/plain:
139+
schema:
140+
type: string
141+
$ref: '#/components/schemas/Log'
142+
responses:
143+
'200':
144+
description: "Log received from <ip_addr> - <ip_addr> is the request's IP address of the application that has sent the message to the LogAggregator"
145+
content:
146+
application/json:
147+
schema:
148+
type: object
149+
example: {"message" : Log received from 127.0.0.1}
150+
'400':
151+
description: "Bad request - check your input"
152+
content:
153+
application/json:
154+
schema:
155+
type: object
156+
example: {"message" : Error upon parsing input payload. Please refer to the documentation to get the correct expected format}
157+
'401':
158+
description: "Unauthorized - missing authorization for requested resource"
159+
160+
161+
components:
162+
securitySchemes:
163+
basicHttpAuthentication:
164+
description: Basic HTTP Authentication
165+
type: http
166+
scheme: Basic
167+
bearerHttpAuthentication:
168+
description: Bearer token using a JWT
169+
type: http
170+
scheme: bearer
171+
bearerFormat: JWT
172+
schemas:
173+
User:
174+
type: object
175+
required:
176+
- username
177+
- password
178+
properties:
179+
username:
180+
type: string
181+
description: Username to be created
182+
password:
183+
type: string
184+
description: Password of the user
185+
Log:
186+
type: string
187+
format: date - time - IP (ipv4 or ipv6) - Process ID - Level - method - module - message
188+
example: 2025-04-18 01:58:39,762 - 127.0.0.1 - 1223 - INFO - get_dns - server.py - Querying DNS server for address www.gmail.com

src/docs/swagger-ui/templates/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<title>Swagger UI</title>
77
<link rel="stylesheet" type="text/css" href="{{ url_for('docs.static', filename='css/swagger-ui.css') }}" />
88
<link rel="stylesheet" type="text/css" href="{{ url_for('docs.static', filename='css/index.css') }}" />
9-
<link rel="icon" type="image/png" href="{{ url_for('docs.static', filename='css/favicon-32x32.png') }}" sizes="32x32" />
10-
<link rel="icon" type="image/png" href="{{ url_for('docs.static', filename='css/favicon-16x16.png') }}" sizes="16x16" />
9+
<link rel="icon" type="image/png" href="{{ url_for('docs.static', filename='png/favicon-32x32.png') }}" sizes="32x32" />
10+
<link rel="icon" type="image/png" href="{{ url_for('docs.static', filename='png/favicon-16x16.png') }}" sizes="16x16" />
1111
</head>
1212

1313
<body>

src/services/auth_service.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ def register_user():
3333
data = request.json
3434
PayloadValidator.validate_payload(data)
3535
user = User.by_id(data['username'])
36-
except ValueError:
36+
except (ValueError, KeyError):
3737
#maybe protecting this against XSS/SQL injection attacks is a good thing...
3838
return jsonify({
3939
"message": "Illegal argument in your request. Please check your input"
40-
}), Constants.HTTP_CONFLICT.value
40+
}), Constants.HTTP_BAD_REQUEST.value
4141
if user:
4242
return jsonify({
4343
"message" : "User already exists"
44-
}), Constants.HTTP_BAD_REQUEST.value
44+
}), Constants.HTTP_CONFLICT.value
4545
new_user = User(
4646
username=data['username']
4747
)
@@ -72,7 +72,7 @@ def login():
7272
"refresh": refresh_token
7373
}
7474
}), Constants.HTTP_OK.value
75-
except KeyError:
75+
except (KeyError, AttributeError):
7676
return jsonify({
7777
"error": "one or more required fields were not provided. Check your input payload"
7878
}), Constants.HTTP_BAD_REQUEST.value

0 commit comments

Comments
 (0)