Metadata-Version: 2.4
Name: pyboot-web
Version: 0.1.13
Summary: Starlette web plugin for PyBoot
License-Expression: MIT
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyboot-framework>=0.1.0
Requires-Dist: starlette>=0.40.0
Requires-Dist: pydantic>=2.0
Requires-Dist: python-dotenv>=1.0.0
Dynamic: license-file

# pyboot-web

`pyboot-web` is the Starlette web plugin for [PyBoot](../../pyboot/README.md).
It adds decorator-based HTTP controllers, route mappings, services, request
middleware, centralized exception handlers, and `.env` configuration loading
to a PyBoot application.

The plugin is intentionally small: PyBoot remains responsible for class
discovery, dependency injection, bean creation, and lifecycle orchestration;
this package translates annotated classes and methods into Starlette routes.

## Documentation

- [Examples](./EXAMPLES.md) - runnable snippets for routing, services,
  middleware, exception advice, and configuration.
- [Production starter](./STARTER.md) - a recommended project layout,
  bootstrap implementation, deployment checklist, and testing approach.
- [License](./LICENSE) - MIT license terms.

## Features

| Capability | API |
| --- | --- |
| HTTP controller | `RestController` |
| HTTP routes | `GetMapping`, `PostMapping`, `PutMapping`, `PatchMapping`, `DeleteMapping` |
| Application services | `Service` |
| PyBoot-managed components | `Component` |
| Bean factories | `Configuration`, `Bean` |
| Middleware | `MiddlewareBase`, `MiddlewareComponent`, `UseMiddleware` |
| Exception advice | `RestControllerAdvice`, `ExceptionHandler` |
| Environment configuration | `Value`, `ValuePlugin` |
| PyBoot integration | `WebPlugin`, registered as the `web` PyBoot plugin |

The package supports Python 3.11 and newer and uses Starlette for routing and
request/response types.

## Installation

Install PyBoot and this plugin in the same environment:

```bash
python -m pip install pyboot-framework pyboot-web
python -m pip install python-dotenv uvicorn
```

For a source checkout, from the repository root:

```bash
python -m pip install -e pyboot
python -m pip install -e plugins/pyboot_web
python -m pip install python-dotenv uvicorn
```

The package metadata declares `starlette`. `python-dotenv` is required by the
`ValuePlugin` implementation.

Verify that PyBoot can discover the plugin entry points:

```bash
python -c "from importlib.metadata import entry_points; print([e.name for e in entry_points(group='pyboot.plugins')])"
```

The output should include `web`. It may also include `value` and other
installed plugins.

## Minimal bootstrap contract

Create a Starlette application, pass it to PyBoot, bootstrap the package that
contains the application classes, and expose the original Starlette object:

```python
from starlette.applications import Starlette
from pyboot.core.application import PyBoot


app = Starlette(debug=False)
PyBoot(app_instance=app, debug=False).bootstrap(package="app")
```

Run it with an ASGI server:

```bash
python -m uvicorn main:app --host 127.0.0.1 --port 8000
```

`PyBoot.bootstrap()` returns `None`; it mutates the supplied Starlette
application by registering routes. Do not assign the return value to `app`.

## API reference

### `pyboot_web.rest_mapping`

- `RestController(path: str)` marks a class as an HTTP controller.
- `GetMapping(path)`, `PostMapping(path)`, `PutMapping(path)`,
  `PatchMapping(path)`, and `DeleteMapping(path)` provide method-specific
  route decorators for methods declared inside a `RestController` class.

Route decorators are intended for controller methods, following the
class-oriented style used by Spring Boot:

```python
@RestController("/api")
class HealthController:
    @GetMapping("/health")
    async def health(self, request: Request) -> JSONResponse:
        ...
```

Supported methods are `GET`, `POST`, `PUT`, `PATCH`, and `DELETE`. A standalone
function decorated as a route is not discovered by `WebPlugin`.

### `pyboot_web.service`

- `Service()` marks a class for web-plugin registration and IoC construction.

Use `Service` for web-layer services. Use PyBoot's built-in `Component` for
general application dependencies that should be managed by the core IoC
container:

```python
from pyboot.core.builtins.component import Component


@Component()
class AuditService:
    ...
```

`Component` classes can be injected into `Service` classes and controllers
when their constructor parameters have type annotations.

### PyBoot built-in bean management

`Component` is the general-purpose PyBoot IoC decorator. For factory-created
objects, use a configuration class with methods annotated by `Bean`:

```python
from pyboot.core.builtins.configuration import Bean, Configuration


class Clock:
    ...


@Configuration()
class ApplicationConfiguration:
    @Bean()
    def clock(self) -> Clock:
        return Clock()
```

The `@Bean` method must have a return annotation. PyBoot registers that return
type as a bean factory, resolves any annotated method dependencies, and creates
the bean through the IoC container. `Component`, `Configuration`, and `Bean`
are core PyBoot features, not web-specific decorators.

### `pyboot_web.middlewares`

- `MiddlewareBase` defines the callable middleware contract.
- `MiddlewareComponent()` marks a middleware class for IoC registration.
- `UseMiddleware(middlewares)` attaches middleware classes to a controller or
  route method.

Pass middleware classes, not instances. The plugin obtains instances from
PyBoot's IoC container.

### `pyboot_web.exception_handler`

- `RestControllerAdvice()` marks an exception advice class.
- `ExceptionHandler(exception_type)` maps an exception type to a handler method.

Handlers receive `(request, exception)` after `self` and should return a
Starlette response. A matching base-class handler can handle subclasses.
Duplicate registrations for the same exception type are rejected. Unhandled
exceptions are re-raised.

### `pyboot_web.value`

- `Value(key, default)` returns an environment value or the supplied default.
- `MissingValueException` is raised when both are `None`.
- `ValuePlugin` loads a discovered `.env` file before class discovery.

Environment values are strings and should be converted explicitly at the
configuration boundary. `ValuePlugin` uses `override=True`, so `.env` values
can replace values already present in the process environment.

### `pyboot_web.plugin`

- `WebPlugin` registers web beans, resolves exception advice, wraps routes with
  middleware and exception handling, and adds routes to the supplied Starlette
  application.

## Discovery and lifecycle

PyBoot loads installed `pyboot.plugins` entry points, imports the package
passed to `bootstrap()`, and scans its submodules for classes defined there.
The web plugin then:

1. Registers `Service`, `Component`, `MiddlewareComponent`,
   `RestControllerAdvice`, and `RestController` classes with the IoC container.
2. Lets PyBoot create registered beans.
3. Registers exception advice handlers.
4. Combines controller and route middleware.
5. Adds annotated controller methods as Starlette routes.

Keep application classes inside the scanned package and keep module-level
side effects small and deterministic. Directories intended as packages should
contain `__init__.py`.

## Compatibility and scope

- This package targets Starlette and does not provide Flask or Django adapters.
- It adds routes to a supplied Starlette application; it does not create one.
- Services and middleware depend on PyBoot IoC registration and constructor
  resolution.
- The package root does not re-export the decorators; import them from their
  defining modules.

## License

This project is distributed under the MIT License. See [LICENSE](./LICENSE).
