Added routers
This commit is contained in:
parent
6a7abd3f95
commit
5fddd43c02
24
README.md
24
README.md
@ -16,6 +16,7 @@ This is a template for building APIs with Clean Architecture. It contains two ex
|
|||||||
## Prepare
|
## Prepare
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
cp envExample .env
|
||||||
make build network
|
make build network
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -25,20 +26,27 @@ make build network
|
|||||||
make api.fastapi.run
|
make api.fastapi.run
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, you can test the API with the following command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -X 'GET' 'http://localhost:8000/api/v1/documents/?appName=app_test&clientId=client_test' -H 'accept: application/json' | jq
|
|
||||||
```
|
|
||||||
|
|
||||||
## Run Flask
|
## Run Flask
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make api.flask.run
|
make api.flask.run
|
||||||
```
|
```
|
||||||
|
## API
|
||||||
|
|
||||||
Now, you can test the API with the following command:
|
### Welcome
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X 'GET' 'http://localhost:5000/api/v1/documents/?appName=app_test&clientId=client_test' -H 'accept: application/json' | jq
|
curl -X 'GET' 'http://localhost:5000' -H 'accept: application/json'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Documents
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X 'GET' 'http://localhost:5000/api/v1/documents/?appName=app_test&clientId=client_test' -H 'accept: application/json'
|
||||||
|
```
|
||||||
|
|
||||||
|
## SEE
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -N -H "Accept:text/event-stream" http://localhost:5000/sse/alerts/
|
||||||
```
|
```
|
||||||
|
0
envExample
Normal file
0
envExample
Normal file
37
src/core/use_case/alerts_use_case.py
Normal file
37
src/core/use_case/alerts_use_case.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
from pydantic import BaseModel, StrictStr, StrictInt
|
||||||
|
|
||||||
|
from src.core.decorators import check_params
|
||||||
|
from faker import Faker
|
||||||
|
from src.core.entity.ResponseTypes import ResponseTypes
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
class GetNextAlertModel(BaseModel):
|
||||||
|
type_alert: StrictStr
|
||||||
|
point: StrictInt
|
||||||
|
|
||||||
|
faker = Faker()
|
||||||
|
|
||||||
|
@check_params(GetNextAlertModel)
|
||||||
|
def get_next_alert(params) -> dict:
|
||||||
|
"""
|
||||||
|
Get next alert
|
||||||
|
|
||||||
|
:param GetNextAlertModel params:
|
||||||
|
:return: dict
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"type": ResponseTypes.SUCCESS,
|
||||||
|
"error": None,
|
||||||
|
"data": {
|
||||||
|
"id": faker.uuid4(),
|
||||||
|
"type": random.choice(["ok", "warning", "danger"]),
|
||||||
|
"message": random.choice([
|
||||||
|
f"The node number {random.randint(1, 8)} needs attention",
|
||||||
|
f"The connection with the node number {random.randint(1, 8)} is unstable",
|
||||||
|
f"The node number {random.randint(1, 8)} is offline",
|
||||||
|
f"The node number {random.randint(1, 8)} is overheating",
|
||||||
|
f"The node number {random.randint(1, 8)} is under maintenance",
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
}
|
@ -2,3 +2,4 @@ FROM base-core-app
|
|||||||
|
|
||||||
# launcher
|
# launcher
|
||||||
ENTRYPOINT flask --app main run --host=0.0.0.0 --debug
|
ENTRYPOINT flask --app main run --host=0.0.0.0 --debug
|
||||||
|
#ENTRYPOINT gunicorn main:app --worker-class gevent --bind 0.0.0.0:5000
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
import os
|
import os
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
from flask import Flask, request
|
from flask import Flask, request, Response
|
||||||
|
|
||||||
from src.core.use_case import documents_use_case
|
|
||||||
from src.infra.storage.AzureStorage import AzureStorage
|
|
||||||
from src.infra.api.flask.middlewares import register_middlewares
|
from src.infra.api.flask.middlewares import register_middlewares
|
||||||
|
from src.infra.api.flask.routes.sse_routes import sse_routes
|
||||||
|
from src.infra.api.flask.routes.api_documents_routes import documents_routes
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
register_middlewares(app)
|
register_middlewares(app)
|
||||||
|
|
||||||
|
# Blueprints
|
||||||
|
app.register_blueprint(documents_routes)
|
||||||
|
app.register_blueprint(sse_routes)
|
||||||
|
|
||||||
@app.route("/api/v1/documents/")
|
@app.route('/')
|
||||||
def documents_list():
|
def index():
|
||||||
storage = AzureStorage(
|
return {'Welcome to Clean Architecture template!': 'The endpoint you are looking for is not in this castle. Read the documentation to find the right path.'}
|
||||||
account_name=os.getenv("AZURE_STORAGE_ACCOUNT_NAME", ""),
|
|
||||||
account_key=os.getenv("AZURE_STORAGE_ACCOUNT_KEY", ""),
|
|
||||||
)
|
|
||||||
params = request.args
|
|
||||||
return documents_use_case.documents_list(storage=storage, params=params)
|
|
||||||
|
@ -69,6 +69,7 @@ def register_middlewares(app):
|
|||||||
"""
|
"""
|
||||||
Convert the keys of the response to camel case (snake_case to camelCase) in all levels
|
Convert the keys of the response to camel case (snake_case to camelCase) in all levels
|
||||||
"""
|
"""
|
||||||
|
if response.status_code == 200 and request.headers.get("Accept", None) != "text/event-stream":
|
||||||
response.data = json.dumps(
|
response.data = json.dumps(
|
||||||
convert_keys_to_camel_case(json.loads(response.data))
|
convert_keys_to_camel_case(json.loads(response.data))
|
||||||
)
|
)
|
||||||
@ -79,6 +80,7 @@ def register_middlewares(app):
|
|||||||
"""
|
"""
|
||||||
Convert the response to JSON format
|
Convert the response to JSON format
|
||||||
"""
|
"""
|
||||||
|
if response.status_code == 200 and request.headers.get("Accept", None) != "text/event-stream":
|
||||||
response.headers["Content-Type"] = "application/json"
|
response.headers["Content-Type"] = "application/json"
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -1 +1,3 @@
|
|||||||
flask
|
flask
|
||||||
|
gunicorn
|
||||||
|
gevent
|
||||||
|
16
src/infra/api/flask/routes/api_documents_routes.py
Normal file
16
src/infra/api/flask/routes/api_documents_routes.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import os
|
||||||
|
from flask import Blueprint, request
|
||||||
|
from src.core.use_case import documents_use_case
|
||||||
|
from src.infra.storage.AzureStorage import AzureStorage
|
||||||
|
|
||||||
|
documents_routes = Blueprint("api_documents_routes", __name__, url_prefix="/api/v1/documents")
|
||||||
|
|
||||||
|
|
||||||
|
@documents_routes.route("/")
|
||||||
|
def documents_list():
|
||||||
|
storage = AzureStorage(
|
||||||
|
account_name=os.getenv("AZURE_STORAGE_ACCOUNT_NAME", ""),
|
||||||
|
account_key=os.getenv("AZURE_STORAGE_ACCOUNT_KEY", ""),
|
||||||
|
)
|
||||||
|
params = request.args
|
||||||
|
return documents_use_case.documents_list(storage=storage, params=params)
|
24
src/infra/api/flask/routes/sse_routes.py
Normal file
24
src/infra/api/flask/routes/sse_routes.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import time
|
||||||
|
import random
|
||||||
|
from flask import Blueprint, Response
|
||||||
|
from src.core.use_case import alerts_use_case
|
||||||
|
|
||||||
|
sse_routes = Blueprint("sse_routes", __name__, url_prefix="/sse")
|
||||||
|
|
||||||
|
@sse_routes.route("/alerts/", methods=["GET"])
|
||||||
|
def sse_alerts():
|
||||||
|
"""
|
||||||
|
SSE endpoint to stream alerts
|
||||||
|
"""
|
||||||
|
def generate():
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
new_data = alerts_use_case.get_next_alert(params={"type_alert": "test", "point": 1})['data']
|
||||||
|
yield f"data: {new_data}\n\n"
|
||||||
|
time.sleep(random.randint(1, 5))
|
||||||
|
except GeneratorExit:
|
||||||
|
print("SSE stream closed")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error in SSE stream: {e}")
|
||||||
|
|
||||||
|
return Response(generate(), content_type="text/event-stream", status=200)
|
Loading…
x
Reference in New Issue
Block a user