Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ Dans le code suivant, il y a plusieurs fonctions qui ont été implémenté dans
Route: '/info/'
Accès : Pas d'accès spécifique

4. Rate Limiting
La fonction rate_limit_middleware agit comme un middleware. Elle prend deux paramètres : request qui représente la
requête HTTP entrante et call_next qui est une fonction représentant le prochain middleware ou le gestionnaire de route réel dans le pipeline de traitement.
Cela nous permet de traiter les requêtes et en locurrence de les limiter afin de ne pas surcharger le server. Nous avons limimé les requêtes à 2 par opérations mathématique en 10 secondes.


### Opérations Mathématiques
1. Power
Description : Calcul de la puissance d'un nombre
Expand Down Expand Up @@ -121,3 +127,8 @@ FastAPI. En effet, lors du lancement de l'application, le programme app.py est e
ajoutées tant que le décorateur n'est pas appelé, c'est-à-dire que les fonctions décorées ne sont pas exécutées une
première fois. Il est alors nécessaire d'appeler chaque fonction dans le programme app afin de rendre utilisable
leur route.


pip install python-multipart
pip install pydantic-settings

31 changes: 25 additions & 6 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
from collections import Counter
import os
import time
from datetime import datetime, timedelta

from functools import wraps

# Load environment variables from a .env file if present
load_dotenv()
Expand All @@ -20,6 +23,7 @@
app = FastAPI(title=sett_Env.title, description=sett_Env.description)
route_request_counter = Counter()
route_time_counter = Counter()
rate_limiting = Counter()


@app.on_event("shutdown")
Expand All @@ -32,7 +36,6 @@ def shutdown_event():
except Exception as e:
print(f"Error deleting statistics file: {e}")


def get_saved_values():
"""
Retrieve the statistics data saved in the file
Expand All @@ -47,7 +50,6 @@ def get_saved_values():
pickle.dump(values, file)
return values


def save_value(values):
"""
Save the current API statistics in a file
Expand All @@ -56,7 +58,6 @@ def save_value(values):
with open("saved_count.pkl", "wb") as file:
pickle.dump(values, file)


@app.middleware("http")
async def count_requests(request: Request, call_next):
"""
Expand All @@ -73,7 +74,6 @@ async def count_requests(request: Request, call_next):
route_time_counter[route] += round(end_time - start_time, 6)
return response


def check_args_type(dict_args, type_args):
"""
Check if args in the dictionary corresponds to the expected type, raise an error if not
Expand All @@ -99,7 +99,6 @@ def count_func_call(func):
request_count[key_func] = 1
save_value(request_count)


def fast_api_decorator(route, method, type_args):
def decorator(func):
def wrapper(**kwargs):
Expand All @@ -114,6 +113,26 @@ def wrapper(**kwargs):
return wrapper
return decorator

# Dictionary to store the last access time for each route
route_last_access = {}
@app.middleware("http")
async def rate_limit_middleware(request: Request, call_next):
route = request.url.path

if route not in route_last_access:
route_last_access[route] = datetime.utcnow()

time_difference = datetime.utcnow() - route_last_access[route]

if time_difference < timedelta(minutes=1):
if route_last_access[route] > datetime.utcnow() - timedelta(seconds=10) and route_last_access[route] != datetime.min:
raise HTTPException(status_code=400, detail="Rate limit exceeded. Try again later.")

route_last_access[route] = datetime.utcnow()

response = await call_next(request)
return response


@fast_api_decorator(route="/power/", method=["GET"], type_args=[int, int])
def power_function(x: Annotated[int, Query(description="Int we'll compute the power")],
Expand Down Expand Up @@ -220,7 +239,7 @@ async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):


@fast_api_decorator(route="/info/me", method=["GET"], type_args=[])
async def info():
def info():
"""
Get information about the application.

Expand Down