perf: optimize dropbox token refresh by replacing blocking requests with httpx

Replaced the synchronous `requests.post` calls in `app/api/dropbox.py` with asynchronous `httpx.AsyncClient().post` calls. This ensures that the FastAPI event loop is not blocked during network I/O, allowing better concurrent performance.

Also updated the `test_api_dropbox.py` tests to use `httpx.AsyncClient.post` in mocks and properly construct `httpx.RequestError` in exception handling tests.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
google-labs-jules[bot]
2026-03-16 09:19:55 +00:00
parent 2732dafba9
commit 84c6e1c5dd
2 changed files with 56 additions and 52 deletions
+7 -4
View File
@@ -6,7 +6,7 @@ import logging
import os import os
from typing import Annotated, Optional from typing import Annotated, Optional
import requests import httpx
from fastapi import APIRouter, Depends, Form, HTTPException, Request, status from fastapi import APIRouter, Depends, Form, HTTPException, Request, status
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@@ -132,9 +132,10 @@ async def test_dropbox_token(request: Request):
"message": "Dropbox credentials are not fully configured", "message": "Dropbox credentials are not fully configured",
} }
async with httpx.AsyncClient() as client:
# Check token validity by getting current account info # Check token validity by getting current account info
headers = {"Authorization": f"Bearer {settings.dropbox_refresh_token}"} headers = {"Authorization": f"Bearer {settings.dropbox_refresh_token}"}
response = requests.post( response = await client.post(
"https://api.dropboxapi.com/2/users/get_current_account", "https://api.dropboxapi.com/2/users/get_current_account",
headers=headers, headers=headers,
timeout=settings.http_request_timeout, timeout=settings.http_request_timeout,
@@ -153,7 +154,9 @@ async def test_dropbox_token(request: Request):
"client_secret": settings.dropbox_app_secret, "client_secret": settings.dropbox_app_secret,
} }
refresh_response = requests.post(refresh_url, data=refresh_data, timeout=settings.http_request_timeout) refresh_response = await client.post(
refresh_url, data=refresh_data, timeout=settings.http_request_timeout
)
if refresh_response.status_code != 200: if refresh_response.status_code != 200:
logger.error(f"Failed to refresh Dropbox token: {refresh_response.text}") logger.error(f"Failed to refresh Dropbox token: {refresh_response.text}")
@@ -168,7 +171,7 @@ async def test_dropbox_token(request: Request):
# Try again with the new access token # Try again with the new access token
headers = {"Authorization": f"Bearer {access_token}"} headers = {"Authorization": f"Bearer {access_token}"}
response = requests.post( response = await client.post(
"https://api.dropboxapi.com/2/users/get_current_account", "https://api.dropboxapi.com/2/users/get_current_account",
headers=headers, headers=headers,
timeout=settings.http_request_timeout, timeout=settings.http_request_timeout,
+7 -6
View File
@@ -137,7 +137,7 @@ class TestTestDropboxToken:
assert data["status"] == "error" assert data["status"] == "error"
assert "not fully configured" in data["message"] assert "not fully configured" in data["message"]
@patch("app.api.dropbox.requests.post") @patch("app.api.dropbox.httpx.AsyncClient.post")
@patch("app.api.dropbox.settings") @patch("app.api.dropbox.settings")
def test_valid_token(self, mock_settings, mock_post, client): def test_valid_token(self, mock_settings, mock_post, client):
"""Test successful token validation.""" """Test successful token validation."""
@@ -162,7 +162,7 @@ class TestTestDropboxToken:
assert data["account"] == "user@example.com" assert data["account"] == "user@example.com"
assert data["account_name"] == "Test User" assert data["account_name"] == "Test User"
@patch("app.api.dropbox.requests.post") @patch("app.api.dropbox.httpx.AsyncClient.post")
@patch("app.api.dropbox.settings") @patch("app.api.dropbox.settings")
def test_expired_token_refreshed(self, mock_settings, mock_post, client): def test_expired_token_refreshed(self, mock_settings, mock_post, client):
"""Test that expired token triggers refresh and retry.""" """Test that expired token triggers refresh and retry."""
@@ -194,7 +194,7 @@ class TestTestDropboxToken:
data = response.json() data = response.json()
assert data["status"] == "success" assert data["status"] == "success"
@patch("app.api.dropbox.requests.post") @patch("app.api.dropbox.httpx.AsyncClient.post")
@patch("app.api.dropbox.settings") @patch("app.api.dropbox.settings")
def test_refresh_token_expired(self, mock_settings, mock_post, client): def test_refresh_token_expired(self, mock_settings, mock_post, client):
"""Test handling when refresh token itself is expired.""" """Test handling when refresh token itself is expired."""
@@ -220,7 +220,7 @@ class TestTestDropboxToken:
assert data["status"] == "error" assert data["status"] == "error"
assert data["needs_reauth"] is True assert data["needs_reauth"] is True
@patch("app.api.dropbox.requests.post") @patch("app.api.dropbox.httpx.AsyncClient.post")
@patch("app.api.dropbox.settings") @patch("app.api.dropbox.settings")
def test_token_validation_failure(self, mock_settings, mock_post, client): def test_token_validation_failure(self, mock_settings, mock_post, client):
"""Test handling non-401, non-200 response.""" """Test handling non-401, non-200 response."""
@@ -240,16 +240,17 @@ class TestTestDropboxToken:
data = response.json() data = response.json()
assert data["status"] == "error" assert data["status"] == "error"
@patch("app.api.dropbox.requests.post") @patch("app.api.dropbox.httpx.AsyncClient.post")
@patch("app.api.dropbox.settings") @patch("app.api.dropbox.settings")
def test_connection_error(self, mock_settings, mock_post, client): def test_connection_error(self, mock_settings, mock_post, client):
"""Test handling of connection exceptions.""" """Test handling of connection exceptions."""
import httpx
mock_settings.dropbox_refresh_token = "token" mock_settings.dropbox_refresh_token = "token"
mock_settings.dropbox_app_key = "app-key" mock_settings.dropbox_app_key = "app-key"
mock_settings.dropbox_app_secret = "app-secret" mock_settings.dropbox_app_secret = "app-secret"
mock_settings.http_request_timeout = 30 mock_settings.http_request_timeout = 30
mock_post.side_effect = requests.exceptions.ConnectionError("Connection refused") mock_post.side_effect = httpx.RequestError("Connection refused", request=httpx.Request("POST", "https://api.dropboxapi.com/2/users/get_current_account"))
response = client.get("/api/dropbox/test-token") response = client.get("/api/dropbox/test-token")