-
Notifications
You must be signed in to change notification settings - Fork 9
Add frontend database routing configuration #242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Add frontend database routing configuration #242
Conversation
When database_frontend is not specified in hardpy.toml, it now automatically falls back to using the same configuration as database. This allows users to: - Use a single database config by default (no database_frontend needed) - Optionally specify a separate frontend database when needed Implementation: - Changed database_frontend to Optional (DatabaseConfig | None) - Added fallback logic in model_post_init - If database_frontend is None, copies database config values 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
This example demonstrates how to configure separate database routing for backend and frontend in containerized environments. Use Case: When running HardPy in Docker containers, the backend and frontend often need different database connection strings: - Backend connects via Docker internal networking (e.g., "couchdb:5984") - Frontend (browser) connects via host exposed ports (e.g., "localhost:5984") Files: - hardpy.toml: Shows database and database_frontend configuration - docker-compose.yaml: Example container setup demonstrating the routing - README.md: Explains when and why to use this configuration - test_simple.py: Basic test file - pytest.ini: Pytest configuration for container environment 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Modified the /api/couch endpoint to use database_frontend.url instead of database.url. This ensures the frontend (browser) connects to the correct database in containerized environments. The frontend already fetches the database connection through this API endpoint (getSyncURL in index.tsx), so no frontend code changes are needed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
| title: str = "HardPy TOML config" | ||
| tests_name: str = "" | ||
| database: DatabaseConfig = DatabaseConfig() | ||
| database_frontend: DatabaseConfig | None = Field(default=None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great suggestion for changes!
To ensure compatibility with future features, I recommend making the following slight modifications to this file and to api.py:
class DatabaseConfig(BaseModel):
"""Database configuration."""
model_config = ConfigDict(extra="forbid")
user: str = "dev"
password: str = "dev"
host: str = "localhost"
port: int = 5984
frontend_host: str = "localhost"
frontend_port: int = 5984
doc_id: str = Field(exclude=True, default="")
url: str = Field(exclude=True, default="")
frontend_url: str = Field(exclude=True, default="")
def model_post_init(self, __context) -> None: # noqa: ANN001,PYI063
"""Get database connection url."""
self.url = self.get_url(self.host, self.port)
self.frontend_url = self.get_url(self.frontend_host, self.frontend_port)
def get_url(self, host: str, port: int) -> str:
"""Get database connection url.
Returns:
str: database connection url
"""
credentials = f"{self.user}:{self.password}"
uri = f"{host}:{port!s}"
return f"http://{credentials}@{uri}/"class HardpyConfig(BaseModel, extra="allow"):
"""HardPy configuration."""
model_config = ConfigDict(extra="forbid")
title: str = "HardPy TOML config"
tests_name: str = ""
database: DatabaseConfig = DatabaseConfig()
frontend: FrontendConfig = FrontendConfig()
stand_cloud: StandCloudConfig = StandCloudConfig()
current_test_config: str = ""
test_configs: list[TestConfig] = []
def model_post_init(self, __context) -> None: # noqa: ANN001,PYI063
"""Get database document name and set database_frontend fallback."""
self.database.doc_id = self.get_doc_id()# init_config() function
self._config.tests_name = tests_name
self._config.frontend.host = frontend_host
self._config.frontend.port = frontend_port
self._config.frontend.language = frontend_language
self._config.database.user = database_user
self._config.database.password = database_password
self._config.database.host = database_host
self._config.database.port = database_port
self._config.database.frontend_host = database_host
self._config.database.frontend_port = database_port
self._config.database.doc_id = self._config.get_doc_id()
self._config.database.url = self._config.database.get_url(
self._config.database.host,
self._config.database.port,
)
self._config.database.frontend_url = self._config.database.get_url(
self._config.database.frontend_host,
self._config.database.frontend_port,
)
self._config.stand_cloud.address = sc_address
self._config.stand_cloud.connection_only = sc_connection_only
self._config.stand_cloud.autosync = sc_autosync
self._config.stand_cloud.api_key = sc_api_keyapi.py
@app.get("/api/couch")
def couch_connection() -> dict:
"""Get couchdb connection string for frontend.
Returns:
dict[str, str]: couchdb connection string
"""
config_manager = ConfigManager()
return {
"connection_str": config_manager.config.database.frontend_url,
}These changes will affect the hardpy.toml file and require a modification to the example, though not a significant one:
[database]
user = "dev"
password = "dev"
host = "couchdb"
port = 5984
frontend_host = "localhost"
frontend_port = 5984| # HardPy backend running tests | ||
| # This would be your test runner container (example only) | ||
| hardpy: | ||
| image: hardpy:latest # Your HardPy image |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you provide an example of a Dockerfile for creating a Docker image to work with HardPy? You could then use it directly in the example.
Summary
This PR adds support for separate database routing for frontend and backend, enabling HardPy to work seamlessly in containerized environments where the backend and frontend (browser) need different database connection strings.
Problem
When running HardPy in Docker containers, the backend and frontend often need different database connection paths:
couchdb:5984)localhost:5984)Previously, both used the same
[database]config, making containerized deployments difficult.Solution
Added an optional
database_frontendconfiguration field that:databaseconfig when not specified (backward compatible)Changes
1. Config Enhancement (
hardpy/common/config.py)database_frontend: DatabaseConfig | None = Field(default=None)model_post_init()to copydatabaseconfig whendatabase_frontendis not specified2. API Update (
hardpy/hardpy_panel/api.py)/api/couchendpoint to usedatabase_frontend.urlinstead ofdatabase.urlgetSyncURL()inindex.tsx3. Complete Example (
examples/frontend_database_routing/)hardpy.tomlwith both database configsBackward Compatibility
✅ Fully backward compatible - existing configs without
[database_frontend]section work unchanged✅ All existing tests pass (214 passed, 9 deselected)
✅ Linting clean with ruff 0.8.0
Testing
Use Cases
Example Configuration
Minimal (uses single database for both):
With separate frontend routing:
If
[database_frontend]is omitted, it automatically uses[database]values.Implementation Details
The feature works through these components:
database_frontend(or falls back todatabase)/api/couchreturnsdatabase_frontend.urlgetSyncURL()fetches from/api/couchand connects to PouchDBdatabase.urlfor test executionThis clean separation allows different routing without duplicating code or breaking existing functionality.