vega-framework 0.1.35__py3-none-any.whl → 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. vega/cli/commands/add.py +9 -10
  2. vega/cli/commands/generate.py +15 -15
  3. vega/cli/commands/init.py +9 -8
  4. vega/cli/commands/web.py +8 -7
  5. vega/cli/main.py +4 -4
  6. vega/cli/scaffolds/__init__.py +6 -2
  7. vega/cli/scaffolds/vega_web.py +109 -0
  8. vega/cli/templates/__init__.py +34 -8
  9. vega/cli/templates/components.py +29 -13
  10. vega/cli/templates/project/ARCHITECTURE.md.j2 +13 -13
  11. vega/cli/templates/project/README.md.j2 +5 -5
  12. vega/cli/templates/web/app.py.j2 +5 -5
  13. vega/cli/templates/web/health_route.py.j2 +2 -2
  14. vega/cli/templates/web/main.py.j2 +2 -3
  15. vega/cli/templates/web/middleware.py.j2 +3 -3
  16. vega/cli/templates/web/router.py.j2 +2 -2
  17. vega/cli/templates/web/routes_init.py.j2 +3 -3
  18. vega/cli/templates/web/routes_init_autodiscovery.py.j2 +2 -2
  19. vega/cli/templates/web/users_route.py.j2 +2 -2
  20. vega/discovery/routes.py +13 -13
  21. vega/web/__init__.py +100 -0
  22. vega/web/application.py +234 -0
  23. vega/web/builtin_middlewares.py +288 -0
  24. vega/web/exceptions.py +151 -0
  25. vega/web/middleware.py +185 -0
  26. vega/web/request.py +120 -0
  27. vega/web/response.py +220 -0
  28. vega/web/route_middleware.py +266 -0
  29. vega/web/router.py +350 -0
  30. vega/web/routing.py +347 -0
  31. {vega_framework-0.1.35.dist-info → vega_framework-0.2.1.dist-info}/METADATA +10 -9
  32. {vega_framework-0.1.35.dist-info → vega_framework-0.2.1.dist-info}/RECORD +35 -24
  33. {vega_framework-0.1.35.dist-info → vega_framework-0.2.1.dist-info}/WHEEL +0 -0
  34. {vega_framework-0.1.35.dist-info → vega_framework-0.2.1.dist-info}/entry_points.txt +0 -0
  35. {vega_framework-0.1.35.dist-info → vega_framework-0.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -38,7 +38,7 @@ The innermost layer containing pure business logic, completely independent of an
38
38
  **Rules:**
39
39
 
40
40
  - ✅ **NO** dependencies on any other layer
41
- - ✅ **NO** framework-specific code (no FastAPI, SQLAlchemy, etc.)
41
+ - ✅ **NO** framework-specific code (no Vega Web, SQLAlchemy, etc.)
42
42
  - ✅ **NO** infrastructure details (no database, HTTP, file system)
43
43
  - ✅ Pure business logic only
44
44
  - ✅ Only defines **interfaces**, never concrete implementations
@@ -90,7 +90,7 @@ Handles user interaction and external communication, acting as the entry point t
90
90
 
91
91
  **Contains:**
92
92
 
93
- - **Web API** - FastAPI routes, controllers, request/response models (when web is enabled)
93
+ - **Web API** - Vega Web routes, controllers, request/response models (when web is enabled)
94
94
  - **CLI** - Command-line interface commands and argument parsing
95
95
  - **GraphQL/gRPC** - Alternative API implementations (if needed)
96
96
  - **WebSockets** - Real-time communication handlers (if needed)
@@ -108,7 +108,7 @@ Handles user interaction and external communication, acting as the entry point t
108
108
  **Examples:**
109
109
 
110
110
  - **CLI**: Uses Click/Typer to define commands that invoke interactors or mediators
111
- - **Web API**: FastAPI endpoints that receive HTTP requests and call domain use cases
111
+ - **Web API**: Vega Web endpoints that receive HTTP requests and call domain use cases
112
112
  - **Both**: Can coexist in the same application, sharing the same business logic
113
113
 
114
114
  ## Core Patterns
@@ -344,7 +344,7 @@ The generator will interactively prompt for:
344
344
 
345
345
  Commands are **automatically discovered** from `presentation/cli/commands/` - no manual registration required.
346
346
 
347
- **FastAPI Routers** - HTTP API endpoints (requires web support):
347
+ **Vega Web Routers** - HTTP API endpoints (requires web support):
348
348
  ```bash
349
349
  vega generate router User
350
350
  vega generate router Product
@@ -353,7 +353,7 @@ vega generate router Order
353
353
 
354
354
  Routers are **automatically discovered** from `presentation/web/routes/` - no manual registration required.
355
355
 
356
- **FastAPI Middleware** - Request/response processing (requires web support):
356
+ **Vega Web Middleware** - Request/response processing (requires web support):
357
357
  ```bash
358
358
  vega generate middleware Logging
359
359
  vega generate middleware Authentication
@@ -362,12 +362,12 @@ vega generate middleware RateLimiting
362
362
 
363
363
  ### Adding Features to Existing Projects
364
364
 
365
- **Add FastAPI Web Support**:
365
+ **Add Vega Web Support**:
366
366
  ```bash
367
367
  vega add web
368
368
  ```
369
369
 
370
- Creates complete FastAPI scaffold:
370
+ Creates complete Vega Web scaffold:
371
371
  - `presentation/web/` directory structure
372
372
  - Routes and middleware setup
373
373
  - Health check endpoints
@@ -482,9 +482,9 @@ vega doctor
482
482
  | `vega generate interactor <Name>` | Generate use case |
483
483
  | `vega generate mediator <Name>` | Generate workflow |
484
484
  | `vega generate command <Name>` | Generate CLI command |
485
- | `vega generate router <Name>` | Generate FastAPI router |
485
+ | `vega generate router <Name>` | Generate Vega Web router |
486
486
  | `vega generate model <Name>` | Generate SQLAlchemy model |
487
- | `vega add web` | Add FastAPI support |
487
+ | `vega add web` | Add Vega Web support |
488
488
  | `vega add sqlalchemy` | Add database support |
489
489
  | `vega migrate <command>` | Manage database migrations |
490
490
  | `vega doctor` | Validate project architecture |
@@ -519,9 +519,9 @@ vega generate router Product
519
519
 
520
520
  This creates `presentation/web/routes/product.py`:
521
521
  ```python
522
- from fastapi import APIRouter
522
+ from vega.web import Router
523
523
 
524
- router = APIRouter() # MUST be named 'router'
524
+ router = Router() # MUST be named 'router'
525
525
 
526
526
  @router.get("/")
527
527
  async def list_products():
@@ -682,7 +682,7 @@ Vega projects follow a standard 4-layer structure:
682
682
  │ └── sendgrid_email_service.py # Sendgrid implementation
683
683
 
684
684
  ├── presentation/ # 🟠 PRESENTATION LAYER (Delivery Mechanisms)
685
- │ ├── web/ # FastAPI web interface (if enabled)
685
+ │ ├── web/ # Vega Web interface (if enabled)
686
686
  │ │ ├── __init__.py
687
687
  │ │ ├── routes/
688
688
  │ │ │ └── user_routes.py
@@ -833,7 +833,7 @@ async def create_user(name: str, email: str):
833
833
 
834
834
  **Benefits:**
835
835
  - Execute async interactors directly in CLI commands
836
- - Same business logic works in both CLI and Web (FastAPI) contexts
836
+ - Same business logic works in both CLI and Web (Vega Web) contexts
837
837
  - Clean async/await syntax
838
838
  - Automatic asyncio event loop management
839
839
 
@@ -20,9 +20,9 @@ Vega Framework application with Clean Architecture.
20
20
  │ └── services/ # Service implementations
21
21
 
22
22
  ├── presentation/ # Delivery mechanisms
23
- │ ├── web/ # FastAPI web interface (if added)
23
+ │ ├── web/ # Vega Web interface (if added)
24
24
  │ │ ├── routes/ # HTTP endpoints
25
- │ │ ├── app.py # FastAPI app factory
25
+ │ │ ├── app.py # Vega app factory
26
26
  │ │ └── main.py # ASGI entrypoint
27
27
  │ └── cli/ # CLI commands
28
28
 
@@ -45,7 +45,7 @@ cp .env.example .env
45
45
  python main.py hello
46
46
  python main.py greet --name John
47
47
 
48
- # If using FastAPI template, run the web server
48
+ # If using web template, run the web server
49
49
  vega web run
50
50
  vega web run --reload # With auto-reload
51
51
  # Visit http://localhost:8000/api/health/status
@@ -81,7 +81,7 @@ vega generate command ListUsers --impl sync
81
81
 
82
82
  ### Add Features
83
83
 
84
- Add FastAPI web support to your project:
84
+ Add Vega Web support to your project:
85
85
 
86
86
  ```bash
87
87
  vega add web
@@ -140,7 +140,7 @@ async def create_user(name: str):
140
140
  click.echo(f"Created: {user.name}")
141
141
  ```
142
142
 
143
- This allows the same async business logic to work in both CLI and web contexts (FastAPI).
143
+ This allows the same async business logic to work in both CLI and web contexts (Vega Web).
144
144
 
145
145
  ## Project Commands Quick Reference
146
146
 
@@ -1,5 +1,5 @@
1
- """FastAPI application factory for {{ project_name }}"""
2
- from fastapi import FastAPI
1
+ """Vega Web application factory for {{ project_name }}"""
2
+ from vega.web import VegaApp
3
3
 
4
4
  from .routes import get_api_router
5
5
 
@@ -8,8 +8,8 @@ APP_TITLE = "{{ project_name.replace('-', ' ').replace('_', ' ').title() }}"
8
8
  APP_VERSION = "0.1.0"
9
9
 
10
10
 
11
- def create_app() -> FastAPI:
12
- """Create and configure FastAPI application"""
13
- app = FastAPI(title=APP_TITLE, version=APP_VERSION)
11
+ def create_app() -> VegaApp:
12
+ """Create and configure Vega Web application"""
13
+ app = VegaApp(title=APP_TITLE, version=APP_VERSION)
14
14
  app.include_router(get_api_router())
15
15
  return app
@@ -1,7 +1,7 @@
1
1
  """Health check endpoints"""
2
- from fastapi import APIRouter
2
+ from vega.web import Router
3
3
 
4
- router = APIRouter()
4
+ router = Router()
5
5
 
6
6
 
7
7
  @router.get("/status", summary="Health status", response_model=dict)
@@ -1,5 +1,4 @@
1
- """FastAPI ASGI entrypoint for {{ project_name }}"""
2
- from fastapi import FastAPI
1
+ """Vega Web ASGI entrypoint for {{ project_name }}"""
3
2
  import config # noqa: F401 - Import to initialize DI container
4
3
 
5
4
  # Auto-discover event subscribers so @subscribe handlers are ready
@@ -12,7 +11,7 @@ else:
12
11
 
13
12
  from .app import create_app
14
13
 
15
- app: FastAPI = create_app()
14
+ app = create_app()
16
15
 
17
16
 
18
17
  if __name__ == "__main__":
@@ -1,5 +1,5 @@
1
- """{{ class_name }} middleware for FastAPI application"""
2
- from fastapi import Request, Response
1
+ """{{ class_name }} middleware for Vega Web application"""
2
+ from vega.web import Request, Response
3
3
  from starlette.middleware.base import BaseHTTPMiddleware
4
4
  from starlette.types import ASGIApp
5
5
  import time
@@ -14,7 +14,7 @@ class {{ class_name }}Middleware(BaseHTTPMiddleware):
14
14
  and responses before they're returned to clients.
15
15
 
16
16
  Usage:
17
- Add to your FastAPI app in app.py:
17
+ Add to your Vega Web app in app.py:
18
18
  from .middleware.{{ file_name }} import {{ class_name }}Middleware
19
19
  app.add_middleware({{ class_name }}Middleware)
20
20
  """
@@ -1,5 +1,5 @@
1
1
  """{{ resource_name }} management endpoints"""
2
- from fastapi import APIRouter, HTTPException, status
2
+ from vega.web import Router, HTTPException, status
3
3
  from typing import List
4
4
 
5
5
  # TODO: Import your Pydantic models here
@@ -8,7 +8,7 @@ from typing import List
8
8
  # TODO: Import your interactors/use cases here
9
9
  # from {{ project_name }}.domain.interactors.{{ resource_file }} import Create{{ resource_name }}, Get{{ resource_name }}, List{{ resource_name }}
10
10
 
11
- router = APIRouter()
11
+ router = Router()
12
12
 
13
13
  # TODO: Remove this in-memory storage and use proper repositories/interactors
14
14
  {{ resource_file }}_db: dict[str, dict] = {}
@@ -1,5 +1,5 @@
1
1
  """API routers aggregation"""
2
- from fastapi import APIRouter
2
+ from vega.web import Router
3
3
 
4
4
  from . import health, users
5
5
 
@@ -7,9 +7,9 @@ from . import health, users
7
7
  API_PREFIX = "/api"
8
8
 
9
9
 
10
- def get_api_router() -> APIRouter:
10
+ def get_api_router() -> Router:
11
11
  """Return application API router"""
12
- router = APIRouter(prefix=API_PREFIX)
12
+ router = Router(prefix=API_PREFIX)
13
13
  router.include_router(health.router, tags=["health"], prefix="/health")
14
14
  router.include_router(users.router, tags=["users"], prefix="/users")
15
15
  return router
@@ -4,9 +4,9 @@ from vega.discovery import discover_routers
4
4
 
5
5
  def get_api_router():
6
6
  """
7
- Auto-discover and register FastAPI routers in this directory.
7
+ Auto-discover and register Vega Web routers in this directory.
8
8
 
9
9
  Returns:
10
- APIRouter: Main API router with all discovered routers included
10
+ Router: Main API router with all discovered routers included
11
11
  """
12
12
  return discover_routers(__package__)
@@ -1,10 +1,10 @@
1
1
  """User management endpoints"""
2
- from fastapi import APIRouter, HTTPException, status
2
+ from vega.web import Router, HTTPException, status
3
3
  from typing import List
4
4
 
5
5
  from ..models.user_models import CreateUserRequest, UserResponse
6
6
 
7
- router = APIRouter()
7
+ router = Router()
8
8
 
9
9
  # In-memory storage for demonstration (replace with repository in production)
10
10
  users_db: dict[str, UserResponse] = {}
vega/discovery/routes.py CHANGED
@@ -1,4 +1,4 @@
1
- """FastAPI router auto-discovery utilities"""
1
+ """Vega Web router auto-discovery utilities"""
2
2
  import importlib
3
3
  import inspect
4
4
  import logging
@@ -6,9 +6,9 @@ from pathlib import Path
6
6
  from typing import Optional
7
7
 
8
8
  try:
9
- from fastapi import APIRouter
9
+ from vega.web import Router
10
10
  except ImportError:
11
- APIRouter = None
11
+ Router = None
12
12
 
13
13
  logger = logging.getLogger(__name__)
14
14
 
@@ -19,12 +19,12 @@ def discover_routers(
19
19
  api_prefix: str = "/api",
20
20
  auto_tags: bool = True,
21
21
  auto_prefix: bool = True
22
- ) -> "APIRouter":
22
+ ) -> "Router":
23
23
  """
24
- Auto-discover and register FastAPI routers from a package.
24
+ Auto-discover and register Vega Web routers from a package.
25
25
 
26
26
  This function scans a package directory for Python modules containing
27
- APIRouter instances named 'router' and automatically registers them
27
+ Router instances named 'router' and automatically registers them
28
28
  with the main router.
29
29
 
30
30
  Args:
@@ -35,7 +35,7 @@ def discover_routers(
35
35
  auto_prefix: Automatically generate prefix from module name (default: True)
36
36
 
37
37
  Returns:
38
- APIRouter: Main router with all discovered routers included
38
+ Router: Main router with all discovered routers included
39
39
 
40
40
  Example:
41
41
  # In your project's presentation/web/routes/__init__.py
@@ -51,15 +51,15 @@ def discover_routers(
51
51
  )
52
52
 
53
53
  Note:
54
- Each route module should export an APIRouter instance named 'router'.
54
+ Each route module should export a Router instance named 'router'.
55
55
  The module filename will be used for tags and prefix generation if enabled.
56
56
  """
57
- if APIRouter is None:
57
+ if Router is None:
58
58
  raise ImportError(
59
- "FastAPI is not installed. Install it with: pip install fastapi"
59
+ "Vega Web is not installed. This should not happen if you're using vega-framework."
60
60
  )
61
61
 
62
- main_router = APIRouter(prefix=api_prefix)
62
+ main_router = Router(prefix=api_prefix)
63
63
 
64
64
  # Resolve the routes package path
65
65
  try:
@@ -90,10 +90,10 @@ def discover_routers(
90
90
  try:
91
91
  module = importlib.import_module(module_name)
92
92
 
93
- # Find APIRouter instance named 'router'
93
+ # Find Router instance named 'router'
94
94
  router = getattr(module, 'router', None)
95
95
 
96
- if isinstance(router, APIRouter):
96
+ if isinstance(router, Router):
97
97
  # Generate tags and prefix from module name
98
98
  if auto_tags:
99
99
  tag = file.stem.replace("_", " ").title()
vega/web/__init__.py ADDED
@@ -0,0 +1,100 @@
1
+ """
2
+ Vega Web Framework
3
+
4
+ A lightweight web framework built on Starlette, providing a FastAPI-like
5
+ developer experience while being deeply integrated with Vega's architecture.
6
+
7
+ Example:
8
+ from vega.web import Router, VegaApp, HTTPException, status
9
+
10
+ router = Router()
11
+
12
+ @router.get("/users/{user_id}")
13
+ async def get_user(user_id: str):
14
+ if user_id == "invalid":
15
+ raise HTTPException(status_code=404, detail="User not found")
16
+ return {"id": user_id, "name": "John"}
17
+
18
+ app = VegaApp(title="My API", version="1.0.0")
19
+ app.include_router(router, prefix="/api")
20
+
21
+ # Run with: uvicorn main:app --reload
22
+ """
23
+
24
+ __version__ = "0.1.0"
25
+
26
+ # Core application
27
+ from .application import VegaApp
28
+
29
+ # Routing
30
+ from .router import Router
31
+
32
+ # Request/Response
33
+ from .request import Request
34
+ from .response import (
35
+ Response,
36
+ JSONResponse,
37
+ HTMLResponse,
38
+ PlainTextResponse,
39
+ RedirectResponse,
40
+ StreamingResponse,
41
+ FileResponse,
42
+ )
43
+
44
+ # Exceptions
45
+ from .exceptions import (
46
+ HTTPException,
47
+ ValidationError,
48
+ NotFoundError,
49
+ UnauthorizedError,
50
+ ForbiddenError,
51
+ BadRequestError,
52
+ status,
53
+ )
54
+
55
+ # Middleware (optional, can be imported explicitly)
56
+ from .middleware import (
57
+ VegaMiddleware,
58
+ CORSMiddleware,
59
+ RequestLoggingMiddleware,
60
+ )
61
+
62
+ # Route middleware
63
+ from .route_middleware import (
64
+ RouteMiddleware,
65
+ MiddlewarePhase,
66
+ middleware,
67
+ )
68
+
69
+ __all__ = [
70
+ # Version
71
+ "__version__",
72
+ # Core
73
+ "VegaApp",
74
+ "Router",
75
+ # Request/Response
76
+ "Request",
77
+ "Response",
78
+ "JSONResponse",
79
+ "HTMLResponse",
80
+ "PlainTextResponse",
81
+ "RedirectResponse",
82
+ "StreamingResponse",
83
+ "FileResponse",
84
+ # Exceptions
85
+ "HTTPException",
86
+ "ValidationError",
87
+ "NotFoundError",
88
+ "UnauthorizedError",
89
+ "ForbiddenError",
90
+ "BadRequestError",
91
+ "status",
92
+ # Middleware
93
+ "VegaMiddleware",
94
+ "CORSMiddleware",
95
+ "RequestLoggingMiddleware",
96
+ # Route Middleware
97
+ "RouteMiddleware",
98
+ "MiddlewarePhase",
99
+ "middleware",
100
+ ]
@@ -0,0 +1,234 @@
1
+ """Main application class for Vega Web Framework"""
2
+
3
+ from typing import Any, Callable, Dict, List, Optional, Sequence
4
+
5
+ from starlette.applications import Starlette
6
+ from starlette.middleware import Middleware
7
+ from starlette.middleware.cors import CORSMiddleware
8
+ from starlette.routing import Mount, Route as StarletteRoute
9
+ from starlette.types import ASGIApp
10
+
11
+ from .router import Router
12
+ from .exceptions import HTTPException
13
+ from .response import JSONResponse
14
+
15
+
16
+ class VegaApp:
17
+ """
18
+ Main application class for Vega Web Framework.
19
+
20
+ This is the core ASGI application that handles all HTTP requests.
21
+ It's built on Starlette but provides a FastAPI-like API for familiarity.
22
+
23
+ Args:
24
+ title: Application title
25
+ description: Application description
26
+ version: Application version
27
+ debug: Enable debug mode
28
+ middleware: List of middleware to apply
29
+ on_startup: Functions to run on startup
30
+ on_shutdown: Functions to run on shutdown
31
+
32
+ Example:
33
+ app = VegaApp(
34
+ title="My API",
35
+ version="1.0.0",
36
+ debug=True
37
+ )
38
+
39
+ @app.get("/")
40
+ async def root():
41
+ return {"message": "Hello World"}
42
+
43
+ # Or with routers
44
+ router = Router(prefix="/api")
45
+ @router.get("/users")
46
+ async def get_users():
47
+ return {"users": []}
48
+
49
+ app.include_router(router)
50
+ """
51
+
52
+ def __init__(
53
+ self,
54
+ *,
55
+ title: str = "Vega API",
56
+ description: str = "",
57
+ version: str = "0.1.0",
58
+ debug: bool = False,
59
+ middleware: Optional[Sequence[Middleware]] = None,
60
+ on_startup: Optional[Sequence[Callable]] = None,
61
+ on_shutdown: Optional[Sequence[Callable]] = None,
62
+ ):
63
+ self.title = title
64
+ self.description = description
65
+ self.version = version
66
+ self.debug = debug
67
+
68
+ # Internal router for top-level routes
69
+ self._router = Router()
70
+
71
+ # Middleware stack
72
+ self._middleware = list(middleware) if middleware else []
73
+
74
+ # Lifecycle handlers
75
+ self._on_startup = list(on_startup) if on_startup else []
76
+ self._on_shutdown = list(on_shutdown) if on_shutdown else []
77
+
78
+ # Starlette app (created lazily)
79
+ self._starlette_app: Optional[Starlette] = None
80
+
81
+ def add_middleware(
82
+ self,
83
+ middleware_class: type,
84
+ **options: Any,
85
+ ) -> None:
86
+ """
87
+ Add middleware to the application.
88
+
89
+ Args:
90
+ middleware_class: Middleware class
91
+ **options: Middleware configuration options
92
+
93
+ Example:
94
+ from starlette.middleware.cors import CORSMiddleware
95
+
96
+ app.add_middleware(
97
+ CORSMiddleware,
98
+ allow_origins=["*"],
99
+ allow_methods=["*"],
100
+ )
101
+ """
102
+ self._middleware.append(Middleware(middleware_class, **options))
103
+ # Invalidate cached Starlette app
104
+ self._starlette_app = None
105
+
106
+ def on_event(self, event_type: str) -> Callable:
107
+ """
108
+ Register lifecycle event handler.
109
+
110
+ Args:
111
+ event_type: Either "startup" or "shutdown"
112
+
113
+ Example:
114
+ @app.on_event("startup")
115
+ async def startup():
116
+ print("Starting up!")
117
+
118
+ @app.on_event("shutdown")
119
+ async def shutdown():
120
+ print("Shutting down!")
121
+ """
122
+
123
+ def decorator(func: Callable) -> Callable:
124
+ if event_type == "startup":
125
+ self._on_startup.append(func)
126
+ elif event_type == "shutdown":
127
+ self._on_shutdown.append(func)
128
+ else:
129
+ raise ValueError(f"Invalid event type: {event_type}")
130
+ # Invalidate cached Starlette app
131
+ self._starlette_app = None
132
+ return func
133
+
134
+ return decorator
135
+
136
+ def include_router(
137
+ self,
138
+ router: Router,
139
+ prefix: str = "",
140
+ tags: Optional[List[str]] = None,
141
+ ) -> None:
142
+ """
143
+ Include a router in the application.
144
+
145
+ Args:
146
+ router: Router to include
147
+ prefix: URL prefix for all routes
148
+ tags: Tags to add to all routes
149
+
150
+ Example:
151
+ users_router = Router()
152
+ @users_router.get("/{user_id}")
153
+ async def get_user(user_id: str):
154
+ return {"id": user_id}
155
+
156
+ app.include_router(users_router, prefix="/users", tags=["users"])
157
+ """
158
+ self._router.include_router(router, prefix=prefix, tags=tags)
159
+ # Invalidate cached Starlette app
160
+ self._starlette_app = None
161
+
162
+ def get(self, path: str, **kwargs: Any) -> Callable:
163
+ """
164
+ Decorator for GET requests.
165
+
166
+ Example:
167
+ @app.get("/items/{item_id}")
168
+ async def get_item(item_id: str):
169
+ return {"id": item_id}
170
+ """
171
+ return self._router.get(path, **kwargs)
172
+
173
+ def post(self, path: str, **kwargs: Any) -> Callable:
174
+ """Decorator for POST requests."""
175
+ return self._router.post(path, **kwargs)
176
+
177
+ def put(self, path: str, **kwargs: Any) -> Callable:
178
+ """Decorator for PUT requests."""
179
+ return self._router.put(path, **kwargs)
180
+
181
+ def patch(self, path: str, **kwargs: Any) -> Callable:
182
+ """Decorator for PATCH requests."""
183
+ return self._router.patch(path, **kwargs)
184
+
185
+ def delete(self, path: str, **kwargs: Any) -> Callable:
186
+ """Decorator for DELETE requests."""
187
+ return self._router.delete(path, **kwargs)
188
+
189
+ def route(self, path: str, methods: List[str], **kwargs: Any) -> Callable:
190
+ """
191
+ Decorator for custom methods.
192
+
193
+ Example:
194
+ @app.route("/items", methods=["GET", "POST"])
195
+ async def items():
196
+ return {"items": []}
197
+ """
198
+ return self._router.route(path, methods, **kwargs)
199
+
200
+ def _build_starlette_app(self) -> Starlette:
201
+ """Build the Starlette application from routes and middleware."""
202
+ # Convert Vega routes to Starlette routes
203
+ starlette_routes = [
204
+ route.to_starlette_route() for route in self._router.get_routes()
205
+ ]
206
+
207
+ # Create Starlette app
208
+ app = Starlette(
209
+ debug=self.debug,
210
+ routes=starlette_routes,
211
+ middleware=self._middleware,
212
+ on_startup=self._on_startup,
213
+ on_shutdown=self._on_shutdown,
214
+ )
215
+
216
+ return app
217
+
218
+ def _get_app(self) -> Starlette:
219
+ """Get or create the Starlette app."""
220
+ if self._starlette_app is None:
221
+ self._starlette_app = self._build_starlette_app()
222
+ return self._starlette_app
223
+
224
+ async def __call__(self, scope: dict, receive: Callable, send: Callable) -> None:
225
+ """
226
+ ASGI application callable.
227
+
228
+ This makes VegaApp a valid ASGI application.
229
+ """
230
+ app = self._get_app()
231
+ await app(scope, receive, send)
232
+
233
+
234
+ __all__ = ["VegaApp"]