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.FileHandler | DirectoryHandler
required
File or folder access service. Use
FileHandler for single-file mode or DirectoryHandler for folder mode.str
default:"file"
Editor mode, either
"file" or "folder". Must match the handler type.FastAPI
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.FileResponse
The main editor application HTML page (
index.html).GET /favicon.ico
Redirect browser default favicon.ico requests to the SVG favicon.RedirectResponse
302 redirect to
/static/favicon.svg.GET /api/mode
Return the current server mode.dict[str, str]
Mode payload with value
"file" or "folder".Example: {"mode": "folder"}GET /api/file-tree
Return the markdown file tree for folder mode.dict[str, Any]
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.dict[str, object]
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.str
required
Full markdown document content to save.
str | None
Relative file path in folder mode. Not used in file mode.
dict[str, object]
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.UploadFile
required
Uploaded image data from multipart form payload.
dict[str, str]
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.str
required
Relative filename under the images directory (e.g.,
"photo.png" or "subdir/photo.png").FileResponse
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.WebSocket
required
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.async method
Accept and register a new WebSocket client.
async method
Remove a WebSocket client from the active set.
async method
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.Callable[[Path], None]
required
Callback invoked on external file changes with the changed file path.
Callable[[], bool]
required
Callback returning
True to ignore events (used to skip internal writes).Path | None
Single-file mode target markdown path. Mutually exclusive with
root_directory.Path | None
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:Source Reference
See the complete implementation inmarkdown_os/server.py.