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
29 changes: 15 additions & 14 deletions backend/python/app/sources/client/http/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def __init__(
token: str,
token_type: str = "Bearer",
timeout: float = 30.0,
follow_redirects: bool = True
follow_redirects: bool = True,
) -> None:
self.headers = {
"Authorization": f"{token_type} {token}",
Expand All @@ -30,8 +30,7 @@ async def _ensure_client(self) -> httpx.AsyncClient:
"""Ensure client is created and available"""
if self.client is None:
self.client = httpx.AsyncClient(
timeout=self.timeout,
follow_redirects=self.follow_redirects
timeout=self.timeout, follow_redirects=self.follow_redirects
)
return self.client

Expand All @@ -43,28 +42,30 @@ async def execute(self, request: HTTPRequest, **kwargs) -> HTTPResponse:
Returns:
A HTTPResponse object containing the response from the server
"""
url = f"{request.url.format(**request.path_params)}"
# Fast URL construction using f-string if path_params present
if request.path_params:
url = request.url.format(**request.path_params)
else:
url = request.url
client = await self._ensure_client()

# Merge client headers with request headers (request headers take precedence)
merged_headers = {**self.headers, **request.headers}
request_kwargs = {
"params": request.query_params,
"headers": merged_headers,
**kwargs
**kwargs,
}

if isinstance(request.body, dict):
# Check if Content-Type indicates form data
content_type = request.headers.get("Content-Type", "").lower()
body = request.body
content_type = request.headers.get("Content-Type", "").lower()
if isinstance(body, dict):
if "application/x-www-form-urlencoded" in content_type:
# Send as form data
request_kwargs["data"] = request.body
request_kwargs["data"] = body
else:
# Send as JSON (default behavior)
request_kwargs["json"] = request.body
elif isinstance(request.body, bytes):
request_kwargs["content"] = request.body
request_kwargs["json"] = body
elif isinstance(body, bytes):
request_kwargs["content"] = body

response = await client.request(request.method, url, **request_kwargs)
return HTTPResponse(response)
Expand Down
1 change: 1 addition & 0 deletions backend/python/app/sources/client/http/http_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class HTTPResponse:
Args:
response: The httpx response object
"""

def __init__(self, response: httpx.Response) -> None:
self.response = response

Expand Down
6 changes: 4 additions & 2 deletions backend/python/app/sources/external/bookstack/bookstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -2481,6 +2481,7 @@ async def update_content_permissions(
"""
params: Dict[str, Union[str, int]] = {}

# Build body dict with conditional assignments (more efficient than repeated updates)
body: Dict[str, Union[str, int, bool, List, Dict, None]] = {}
if owner_id is not None:
body["owner_id"] = owner_id
Expand All @@ -2489,9 +2490,10 @@ async def update_content_permissions(
if fallback_permissions is not None:
body["fallback_permissions"] = fallback_permissions

url = self.base_url + "/api/content-permissions/{content_type}/{content_id}".format(content_type=content_type, content_id=content_id)
# Faster URL formatting via f-string instead of str.format
url = f"{self.base_url}/api/content-permissions/{content_type}/{content_id}"

headers = dict(self.http.headers)
headers = self.http.headers.copy()
headers['Content-Type'] = 'application/json'

request = HTTPRequest(
Expand Down