Skip to content
141 changes: 141 additions & 0 deletions blacksheep/docs/application.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,156 @@ the environment variable `APP_SHOW_ERROR_DETAILS` to control whether the
application displays detailed error information. Setting
`APP_SHOW_ERROR_DETAILS=1` or `APP_SHOW_ERROR_DETAILS=True` enables this
feature.

///

/// admonition | Settings strategy

BlackSheep project templates include a strategy to handle application
settings and configuration roots. Refer to [_Getting started with the MVC project template_](./mvc-project-template.md)
for more information.

///

## EnvironmentSettings

Starting from BlackSheep 2.4.4, the `Application` object includes an `env_settings`
property that provides runtime access to environment-based configuration settings.
The `Application` object automatically attaches an `EnvironmentSettings` instance that
contains configuration values read from environment variables. This feature provides
transparency and enables runtime inspection of the application's configuration, which
is useful for debugging, testing, and administrative purposes.

### Accessing Environment Settings

You can access the environment settings through the `env_settings` property:

```python
from blacksheep import Application

app = Application()

# Access environment settings at runtime
print(f"Show error details: {app.env_settings.show_error_details}")
print(f"Force HTTPS: {app.env_settings.force_https}")
print(f"HTTP scheme: {app.env_settings.http_scheme}")
```

### Available Environment Settings

The `EnvironmentSettings` object includes the following properties (all read-only):

| Property | Environment Variable | Type | Default | Description |
| -------------------- | ------------------------ | ------------ | ------- | --------------------------------------------- |
| `env` | `APP_ENV` | `str` | `"production"` | Application environment (e.g., "local", "dev", "production") |
| `show_error_details` | `APP_SHOW_ERROR_DETAILS` | `bool` | `False` | Whether to display detailed error information |
| `mount_auto_events` | `APP_MOUNT_AUTO_EVENTS` | `bool` | `True` | Whether to automatically mount application events |
| `use_default_router` | `APP_DEFAULT_ROUTER` | `bool` | `True` | Whether to use the default router |
| `add_signal_handler` | `APP_SIGNAL_HANDLER` | `bool` | `False` | Whether to add signal handlers for graceful shutdown |
| `http_scheme` | `APP_HTTP_SCHEME` | `str | None` | `None` | Explicitly set request scheme (`http` or `https`) |
| `force_https` | `APP_FORCE_HTTPS` | `bool` | `False` | Whether to force HTTPS scheme and enable HSTS |

Refer to [_Settings_](./settings.md) for more information.

### Practical Use Cases

#### Testing and Assertions

Environment settings are particularly useful for testing configuration:

```python
import os
from blacksheep import Application

# Set environment variable
os.environ["APP_FORCE_HTTPS"] = "true"

app = Application()

# Assert configuration in tests
assert app.env_settings.force_https is True
assert app.env_settings.http_scheme is None # Not set

# Clean up
del os.environ["APP_FORCE_HTTPS"]
```

#### Health Check Endpoints

Create health check endpoints that expose configuration information:

```python
from blacksheep import Application, get

app = Application()

@get("/health")
async def health_check():
return {
"status": "healthy",
"config": {
"force_https": app.env_settings.force_https,
"http_scheme": app.env_settings.http_scheme,
"show_error_details": app.env_settings.show_error_details
}
}
```

#### Admin Tools and Configuration Inspection

Build administrative interfaces that display current configuration:

```python
from blacksheep import Application, get
from blacksheep.server.authorization import auth

app = Application()

@auth(roles=["admin"])
@get("/admin/config")
async def admin_config():
"""Administrative endpoint to inspect application configuration"""
return {
"environment_settings": {
"show_error_details": app.env_settings.show_error_details,
"force_https": app.env_settings.force_https,
"http_scheme": app.env_settings.http_scheme,
},
"runtime_info": {
"debug_mode": app.debug,
"middleware_count": len(app.middlewares),
}
}
```

#### Debugging and Development

Use environment settings for conditional debugging logic:

```python
from blacksheep import Application

app = Application()

@app.on_start
async def configure_logging():
if app.env_settings.show_error_details:
# Enable verbose logging in development
import logging
logging.getLogger().setLevel(logging.DEBUG)
print("Debug logging enabled due to APP_SHOW_ERROR_DETAILS=true")
```

### Benefits of Runtime Configuration Access

1. **Transparency**: Easy inspection of how the application is configured
2. **Testing**: Reliable assertions about configuration state in tests
3. **Debugging**: Quick access to configuration values during development
4. **Monitoring**: Health checks and admin endpoints can expose configuration
5. **Conditional Logic**: Runtime decisions based on configuration values

The `EnvironmentSettings` object is read-only, ensuring that configuration remains stable throughout the application lifecycle while still providing full visibility into the current settings.

### Configuring exceptions handlers

The BlackSheep `Application` object has an `exceptions_handlers` dictionary
Expand Down
6 changes: 3 additions & 3 deletions blacksheep/docs/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ app.use_authentication().add(
valid_audiences=["my-service"],
valid_issuers=["my-issuer"],
algorithms=["HS256"], # ⟵ symmetric algorithms: HS256, HS384, HS512
auth_mode="JWT Symmetric"
scheme="JWT Symmetric"
)
)

Expand Down Expand Up @@ -840,7 +840,7 @@ app.use_authentication().add(
valid_audiences=["internal-api"],
valid_issuers=["internal-issuer"],
algorithms=["HS256"],
auth_mode="JWT Internal"
scheme="JWT Internal"
)
)

Expand All @@ -851,7 +851,7 @@ app.use_authentication().add(
valid_audiences=["external-client-id"],
valid_issuers=["https://login.microsoftonline.com/tenant-id/v2.0"],
algorithms=["RS256"],
auth_mode="JWT External"
scheme="JWT External"
)
)
```
Expand Down
12 changes: 6 additions & 6 deletions blacksheep/docs/authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class ExampleAuthHandler(AuthenticationHandler):
def __init__(self):
pass

async def authenticate(self, context: Request) -> Optional[Identity]:
async def authenticate(self, context: Request) -> Identity | None:
header_value = context.get_first_header(b"Authorization")
if header_value:
# TODO: parse and validate the value of the authorization
Expand All @@ -62,7 +62,7 @@ app.use_authorization().add(Policy(Authenticated, AuthenticatedRequirement()))


@get("/")
async def for_anybody(user: Optional[User]):
async def for_anybody(user: User | None):
if user is None:
return json({"anonymous": True})

Expand Down Expand Up @@ -138,7 +138,7 @@ class ExampleAuthHandler(AuthenticationHandler):
def __init__(self):
pass

async def authenticate(self, context: Request) -> Optional[Identity]:
async def authenticate(self, context: Request) -> Identity | None:
header_value = context.get_first_header(b"Authorization")
if header_value:
# TODO: parse and validate the value of the authorization
Expand Down Expand Up @@ -173,7 +173,7 @@ app.use_authorization().add(Policy(Authenticated, AuthenticatedRequirement())).a


@get("/")
async def for_anybody(user: Optional[User]):
async def for_anybody(user: User | None):
# This method can be used by anybody
if user is None:
return json({"anonymous": True})
Expand Down Expand Up @@ -220,7 +220,7 @@ from blacksheep.server.authorization import allow_anonymous

@allow_anonymous()
@get("/")
async def for_anybody(user: Optional[User]):
async def for_anybody(user: User | None):
if user is None:
return json({"anonymous": True})

Expand Down Expand Up @@ -248,7 +248,7 @@ class GitHubAuthHandler(AuthenticationHandler):
def scheme(self) -> str:
return "github"

async def authenticate(self, context: Request) -> Optional[Identity]:
async def authenticate(self, context: Request) -> Identity | None:
...


Expand Down
Loading