server.py module provides the create_app() factory function that creates a FastAPI application with all routes, WebSocket support, and file system watching for the markdown editor.
create_app()
Create the FastAPI application for the markdown editor.File or folder access service. Use
FileHandler for single-file mode or DirectoryHandler for folder mode.Editor mode, either
"file" or "folder". Must match the handler type.Configured FastAPI application with routes, static assets, WebSocket support, and file system watching.
ValueError- If mode is not"file"or"folder"
Example
Application Lifecycle
The application uses FastAPI’s lifespan context manager to start and stop file system observers:HTTP Routes
GET /
Serve the editor web page.The main editor application HTML page (
index.html).GET /favicon.ico
Redirect browser default favicon.ico requests to the SVG favicon.302 redirect to
/static/favicon.svg.GET /api/mode
Return the current server mode.Mode payload with value
"file" or "folder".Example: {"mode": "folder"}GET /api/file-tree
Return the markdown file tree for folder mode.Nested folder/file structure (see
DirectoryHandler.get_file_tree() for schema).GET /api/content
Return markdown content and metadata.str | None
Relative file path in folder mode (e.g.,
?file=guides/intro.md). Not used in file mode.Response containing:
content(str): Markdown content as UTF-8 stringmetadata(dict): File metadata fromFileHandler.get_metadata()- In folder mode, includes additional
relative_pathfield
- In folder mode, includes additional
HTTPException(400)- Iffileparameter missing in folder mode or path invalidHTTPException(404)- If file does not existHTTPException(500)- If file read fails
POST /api/save
Persist markdown content to disk with atomic file replacement.Full markdown document content to save.
Relative file path in folder mode. Not used in file mode.
Response containing:
status(str): Always"saved"on successmetadata(dict): Updated file metadata after save
HTTPException(400)- Iffileparameter missing in folder mode or path invalidHTTPException(404)- If file does not existHTTPException(500)- If write fails
The server tracks internal writes with a timestamp to distinguish them from external file changes when file watching.
POST /api/images
Save an uploaded image in the workspace images directory.Uploaded image data from multipart form payload.
Response containing:
path(str): Relative image path for markdown (e.g.,"images/photo-20240301-123456.png")filename(str): Saved filename with timestamp
- Allowed extensions:
.png,.jpg,.jpeg,.gif,.webp,.svg,.bmp,.ico - Maximum size: 10 MB (10,485,760 bytes)
- Filename sanitization: Non-alphanumeric characters replaced with hyphens, timestamp appended
HTTPException(400)- If file format unsupported, empty, or too large
GET /images/{filename:path}
Serve uploaded images from the workspace images directory.Relative filename under the images directory (e.g.,
"photo.png" or "subdir/photo.png").Streamed image file response when present.
HTTPException(400)- If path contains..or escapes images directoryHTTPException(404)- If image not found
WebSocket Routes
WS /ws
Maintain WebSocket connections for external file-change notifications.Incoming WebSocket connection from the browser.
The WebSocket connection stays open until the client disconnects. Clients should reconnect automatically if the connection drops.
- Accepts connection and registers client in
WebSocketHub - Keeps connection alive by receiving (and ignoring) client messages
- Removes client on disconnect or error
- Receives external file change notifications from watchdog observer
Helper Classes
WebSocketHub
Manage active WebSocket clients and fan-out messages.Accept and register a new WebSocket client.
Remove a WebSocket client from the active set.
Send a JSON payload to all currently connected clients. Automatically removes stale clients that fail to receive.
MarkdownPathEventHandler
Watchdog handler for markdown file changes in file or folder mode.Callback invoked on external file changes with the changed file path.
Callback returning
True to ignore events (used to skip internal writes).Single-file mode target markdown path. Mutually exclusive with
root_directory.Folder-mode workspace root path. Mutually exclusive with
target_file.- Listens for
modified,moved, andcreatedevents - Filters out directory events (only files)
- Validates events match target file or are markdown files in root directory
- Throttles to max one notification per 0.2 seconds
- Ignores events within 0.5 seconds of internal writes
App State
The FastAPI app stores state inapp.state:
Complete Server Example
File Watching Details
Watch Configuration
File Mode:- Watches: Parent directory of target file
- Recursive: No
- Events: Only for the specific target file
- Watches: Entire workspace directory
- Recursive: Yes
- Events: All
.mdand.markdownfiles
Event Throttling
The file watcher implements two throttling mechanisms:- Time-based throttling: Maximum one notification per 0.2 seconds
- Internal write filtering: Ignores events within 0.5 seconds of
POST /api/saverequests
This prevents the editor from receiving notifications for its own save operations, which would cause unnecessary UI updates and potential conflicts.
Static Files
Static assets are mounted frommarkdown_os/static/:
/static/index.html- Main editor HTML/static/js/*.js- JavaScript modules/static/css/*.css- Stylesheets/static/favicon.svg- Application icon
Error Handling
The server maps internal exceptions to HTTP status codes:| Exception | Status Code | Scenario |
|---|---|---|
FileReadError (“does not exist”) | 404 | File not found |
FileReadError (other) | 500 | Read failure |
FileWriteError | 500 | Write failure |
FileNotFoundError | 404 | File not found |
ValueError | 400 | Invalid path or parameter |
Source Reference
See the complete implementation inmarkdown_os/server.py.