diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 36519dd..923e13b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -25,7 +25,9 @@ jobs: restore-keys: | mkdocs-material- - run: sudo apt-get install libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev - - run: pip install git+https://${GH_TOKEN}@github.com/squidfunk/mkdocs-material-insiders.git pillow cairosvg + - run: pip install --extra-index-url=$EXTRA_INDEX_URL mkdocs-material pillow cairosvg + env: + EXTRA_INDEX_URL: ${{ secrets.EXTRA_INDEX_URL }} - run: mkdocs gh-deploy --force env: GH_TOKEN: ${{ secrets.GH_TOKEN }} diff --git a/docs/blog/posts/websockets_exception.md b/docs/blog/posts/websockets_exception.md new file mode 100644 index 0000000..f110060 --- /dev/null +++ b/docs/blog/posts/websockets_exception.md @@ -0,0 +1,89 @@ +--- +date: 2024-05-12 +categories: +- WebSockets +readtime: 5 +--- + +# Managing Exceptions in WebSockets with FastAPI + +In this post, we delve into the management of exceptions in WebSockets, focusing on a potent but often +overlooked feature: the `WebSocketException` offered by [Starlette][starlette]. + +## Understanding `WebSocketException` + +Conceptually, `WebSocketException` enables you to close a WebSocket connection with a specific code and reason +by raising this exception in your WebSocket route. Here's an illustrative example: + +```python +from fastapi import FastAPI, WebSocket +from fastapi.exceptions import WebSocketException + +app = FastAPI() + +@app.websocket("/ws") +async def websocket_endpoint(websocket: WebSocket): + await websocket.accept() + raise WebSocketException(code=1008, reason="Closing the connection...") +``` + +In this instance, a `WebSocketException` is raised bearing the code `1008` and the explicit reason for closure: `"Closing the connection..."`. + +To run this application, first install FastAPI, Uvicorn, and WebSockets: + +```bash +pip install fastapi uvicorn websockets +``` + +Run the application using Uvicorn: + +``` +uvicorn main:app --reload +``` + +On opening a WebSocket connection to ws://localhost:8000/ws, you will find the connection being closed with focal code +1008 and the attributed reason. + +I use wscat for testing WebSocket connections; you can install it with the following command: + +```bash +npm install -g wscat +``` + +A connection is opened with: + +```bash +wscat -c ws://127.0.0.1:8000/ws +``` + +## Handle custom exceptions + +The `app.exception_handler` can be used to handle custom exceptions. Consider the following sample: + +```python +from fastapi import FastAPI, WebSocket +from fastapi.exceptions import WebSocketException + +app = FastAPI() + +class CustomException(Exception): ... + +@app.exception_handler(CustomException) +async def custom_exception_handler(websocket: WebSocket, exc: Exception): + await websocket.close(code=1008, reason="Custom exception") + +@app.websocket("/ws") +async def websocket_endpoint(websocket: WebSocket): + await websocket.accept() + raise CustomException() +``` + +In this example, the client receives a WebSocket closure with code 1008 and the reason "Custom exception" +when the `CustomException` is raised. + +Feel free to connect with me on [LinkedIn][linkedin] for any questions or discussions on this topic. + +Happy coding! 🚀 + +[starlette]: https://www.starlette.io/websockets/ +[linkedin]: https://www.linkedin.com/in/marcelotryle/ diff --git a/mkdocs.yml b/mkdocs.yml index e6ea32a..af47ab4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -16,6 +16,7 @@ theme: features: - navigation.tabs - content.code.annotate + - content.code.copy palette: # Palette toggle for light mode