Skip to content

Websockets#90

Merged
michael-pisman merged 43 commits intomainfrom
websocket
Jul 30, 2025
Merged

Websockets#90
michael-pisman merged 43 commits intomainfrom
websocket

Conversation

@michael-pisman
Copy link
Member

This pull request introduces significant updates to the unipoll_api project, focusing on enhancing modularity, adding WebSocket support, improving API versioning, and refining exception handling. The most notable changes include the introduction of WebSocket actions and exceptions, the implementation of API versioning with separate routers for v1 and v2, and the addition of Swagger documentation endpoints. Below is a breakdown of the key changes:

WebSocket Support

  • Added a new websocket module with comprehensive WebSocket-related actions for managing workspaces and groups, such as retrieving members, adding members, and handling policies (src/unipoll_api/actions/websocket.py).
  • Introduced WebSocket-specific exceptions, including AuthenticationError, InvalidAction, and InvalidMessageData, to standardize error handling for WebSocket interactions (src/unipoll_api/exceptions/websocket.py).

API Versioning and Routing

  • Replaced the single router with a create_router function to enable API versioning. Added separate routers for v1 and v2 endpoints, and integrated WebSocket routes (src/unipoll_api/routes/__init__.py, src/unipoll_api/routes/v1/__init__.py) [1] [2].
  • Disabled default FastAPI documentation (docs_url and redoc_url) and added custom Swagger and ReDoc endpoints for both default and versioned APIs (src/unipoll_api/app.py, src/unipoll_api/routes/swagger_docs.py) [1] [2].

Dependency and Authentication Enhancements

  • Updated websocket_auth to validate WebSocket tokens using a database strategy and return the authenticated user (src/unipoll_api/dependencies.py).
  • Refined the active_user context variable to include type annotations for better type safety (src/unipoll_api/account_manager.py).

Code Modularity and Cleanup

  • Modularized the routes by splitting them into versioned directories (src/unipoll_api/routes/v1/account.py, src/unipoll_api/routes/v1/__init__.py) [1] [2].
  • Simplified and clarified code formatting in various files, such as get_members and create_poll, for improved readability (src/unipoll_api/actions/members.py, src/unipoll_api/actions/poll.py) [1] [2].

Minor Updates

  • Added imports for the new websocket module and WebSocket exceptions in relevant files (src/unipoll_api/actions/__init__.py, src/unipoll_api/exceptions/__init__.py) [1] [2].

Changed accidental action to workspace
Added routes to get and create members
fastapi-versioning and fastapi-versionizer libraries had too many issues, so a custom functionaly has been added to handle multiple versions of the API
Created a custom system for versioning API based on standart fastapi functionality. The api_version.py contains disctionary with openAPI schemas generated during application's initial stage. The routers have been separated by prefix, with an ability to select custom router. The swagger_docs.py contains router for documentation endpoints.
Added two endpoints, similar to the Doc endpoints, to get ReDoc documentation of the default API version or specified version of the API based on path parameter
Changed the order in v2 routers are added, which affects in which order they are listed in the documentation
Changed the order in which v1 routers are added, which affects in which order they are listed in the documentation
…nerating unique operation IDs based on provided API version
websocket_auth dependency returns current user
Changed disconnect method to be asynchronous
Added filter_arguments function
Copilot AI review requested due to automatic review settings July 30, 2025 06:13
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request introduces comprehensive WebSocket support and API versioning to the unipoll_api project. The changes modernize the API architecture by implementing versioned endpoints (v1 and v2), adding real-time WebSocket functionality, and improving documentation capabilities.

  • Adds WebSocket support with actions for workspace/group management and real-time communication
  • Implements API versioning with separate routers for v1 and v2 endpoints
  • Introduces custom documentation endpoints with versioned Swagger/ReDoc support

Reviewed Changes

Copilot reviewed 29 out of 34 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/unipoll_api/websocket_manager.py Adds WebSocket connection management and message parsing functionality
src/unipoll_api/utils/api_versioning.py Implements OpenAPI schema management for API versioning
src/unipoll_api/schemas/websocket.py Defines WebSocket message schema
src/unipoll_api/routes/websocket.py Implements WebSocket endpoint with authentication and message handling
src/unipoll_api/routes/v2/*.py Adds v2 API endpoints for workspaces, groups, polls, and other resources
src/unipoll_api/routes/v1/*.py Refactors existing endpoints into v1 versioned structure
src/unipoll_api/routes/swagger_docs.py Creates custom documentation endpoints for versioned APIs
src/unipoll_api/routes/init.py Refactors routing to support API versioning and WebSocket integration
src/unipoll_api/exceptions/websocket.py Defines WebSocket-specific exception classes
src/unipoll_api/actions/websocket.py Implements WebSocket action handlers for various operations
Comments suppressed due to low confidence (2)

Comment on lines 21 to +26
async def send_personal_message(self, message: str, websocket: WebSocket) -> None:
await websocket.send_text(message)
await websocket.send_json(message)

async def broadcast(self, message: str) -> None:
for connection in self.active_connections:
await connection.send_text(message)
await connection.send_json(message)
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The parameter name 'message' suggests a string, but the method is sending JSON. Consider renaming the parameter to 'data' or 'json_data' to better reflect the expected data type.

Copilot uses AI. Check for mistakes.
Comment on lines 21 to +26
async def send_personal_message(self, message: str, websocket: WebSocket) -> None:
await websocket.send_text(message)
await websocket.send_json(message)

async def broadcast(self, message: str) -> None:
for connection in self.active_connections:
await connection.send_text(message)
await connection.send_json(message)
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Similar to send_personal_message, the parameter name 'message' suggests a string, but the method is sending JSON. Consider renaming for consistency.

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +56
response = {"status": "success"}
return response.model_dump(exclude_none=True)
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code returns a dictionary from model_dump() when a BaseModel is expected according to the return type annotation. Either change the return type to 'dict' or return the BaseModel instance directly.

Suggested change
response = {"status": "success"}
return response.model_dump(exclude_none=True)
response = SuccessResponse(status="success")
return response

Copilot uses AI. Check for mistakes.
return await WorkspaceActions.create_workspace(data)


async def get_workspace_info(workspace_id: ResourceID):
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable 'args' is referenced but not defined in this function. This will result in a NameError at runtime.

Suggested change
async def get_workspace_info(workspace_id: ResourceID):
async def get_workspace_info(workspace_id: ResourceID, **args):

Copilot uses AI. Check for mistakes.
account: Account = Depends(Dependencies.get_account)):
member: Member = Depends(Dependencies.get_member)):
try:
return await MembersActions.remove_member(group, account)
Copy link

Copilot AI Jul 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable 'account' is referenced but the parameter is named 'member'. This should be 'member' to match the function parameter.

Suggested change
return await MembersActions.remove_member(group, account)
return await MembersActions.remove_member(group, member)

Copilot uses AI. Check for mistakes.
@michael-pisman michael-pisman merged commit 70ae2f3 into main Jul 30, 2025
1 check failed
@michael-pisman michael-pisman deleted the websocket branch July 30, 2025 06:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant