{"id":30681509,"url":"https://github.com/lsfratel/webspark","last_synced_at":"2026-05-06T04:32:52.380Z","repository":{"id":310405537,"uuid":"1039720257","full_name":"lsfratel/webspark","owner":"lsfratel","description":"A lightweight and minimalist Python web framework for building fast WSGI applications and APIs.","archived":false,"fork":false,"pushed_at":"2025-08-26T18:19:51.000Z","size":221,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-01T17:56:25.030Z","etag":null,"topics":["bottlepy","django","django-rest-framework","flask","python","web-framework"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lsfratel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-17T20:58:38.000Z","updated_at":"2025-08-26T15:43:16.000Z","dependencies_parsed_at":"2025-08-17T23:34:43.339Z","dependency_job_id":null,"html_url":"https://github.com/lsfratel/webspark","commit_stats":null,"previous_names":["lsfratel/webspark"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lsfratel/webspark","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lsfratel%2Fwebspark","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lsfratel%2Fwebspark/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lsfratel%2Fwebspark/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lsfratel%2Fwebspark/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lsfratel","download_url":"https://codeload.github.com/lsfratel/webspark/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lsfratel%2Fwebspark/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32678618,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T02:33:58.958Z","status":"ssl_error","status_checked_at":"2026-05-06T02:33:39.611Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bottlepy","django","django-rest-framework","flask","python","web-framework"],"created_at":"2025-09-01T17:51:57.052Z","updated_at":"2026-05-06T04:32:52.360Z","avatar_url":"https://github.com/lsfratel.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebSpark ✨\n\n**A lightweight, minimalist Python web framework for building WSGI applications and APIs.**\n\n[![Code Coverage](https://img.shields.io/codecov/c/github/lsfratel/webspark?style=for-the-badge)](https://codecov.io/gh/lsfratel/webspark)\n[![License](https://img.shields.io/github/license/lsfratel/webspark?style=for-the-badge)](https://github.com/lsfratel/webspark/blob/main/LICENSE)\n\nWebSpark provides a simple yet powerful architecture for handling HTTP requests and responses, featuring a robust routing system, class-based views, middleware support, and a powerful data validation engine. It's designed for developers who want speed and flexibility without the overhead of a larger framework.\n\n## Features\n\n-   **Zero Runtime Dependencies**: A pure WSGI framework with no external dependencies required.\n-   **Powerful Routing**: Flexible, parameterized routing with support for nesting and wildcards.\n-   **Class-Based Views**: Intuitive request handling with automatic dispatching based on HTTP methods.\n-   **Data Validation**: A declarative schema system for validating request bodies and query parameters.\n-   **Middleware via Plugins**: A simple plugin system for request/response processing and cross-cutting concerns.\n-   **Method-Level Plugin Application**: Apply plugins directly to view methods using the `apply` helper.\n-   **Modern HTTP Toolkit**: Clean abstractions for Requests, Responses, and Cookies.\n-   **Optimized JSON Handling**: Automatically uses the fastest available JSON library (`orjson`, `ujson`, or `json`).\n-   **Built-in File Uploads**: Seamlessly handle multipart form data and file uploads.\n-   **Comprehensive Error Handling**: A simple `HTTPException` system for clear and consistent error responses.\n-   **Proxy Support**: Built-in support for running behind a reverse proxy.\n-   **Environment Configuration**: Helper utilities for managing configuration via environment variables.\n-   **Extensive Testing**: 90% test coverage ensuring reliability and stability.\n\n## Installation\n\nInstall WebSpark directly from GitHub using `pip`:\n\n```bash\npip install git+https://github.com/lsfratel/webspark.git\n```\n\nOr, if you are developing locally with [PDM](https://pdm-project.org/):\n\n```bash\n# Clone the repository\ngit clone https://github.com/lsfratel/webspark.git\ncd webspark\n\n# Install dependencies with PDM\npdm install\n```\n\n## Quick Start\n\nCreate a file named `app.py` and get a server running in under a minute.\n\n```python\n# app.py\nfrom webspark.core import WebSpark, View, path\nfrom webspark.http import Context\n\n# 1. Define a View\nclass HelloView(View):\n    \"\"\"A view to handle requests to the root URL.\"\"\"\n    def handle_get(self, ctx: Context):\n        # The `handle_get` method is automatically called for GET requests.\n        ctx.json({\"message\": \"Hello, from WebSpark! ✨\"})\n\n# 2. Create the application instance\napp = WebSpark()\n\n# 3. Add the route to the application\napp.add_paths([\n    path(\"/\", view=HelloView.as_view())\n])\n\n# 4. To run, use a WSGI server like Gunicorn:\n# gunicorn app:app\n```\n\nNow, run your application with a WSGI server:\n\n```bash\ngunicorn app:app\n```\n\nOpen your browser to `http://127.0.0.1:8000`, and you should see the JSON response!\n\n## More Examples\n\nCheck out the [examples](examples/) directory for more comprehensive examples:\n\n1. **[Basic API](examples/basic_api.py)** - A simple REST API with CRUD operations\n2. **[Schema Validation](examples/schema_example.py)** - Data validation with schemas\n3. **[Plugins/Middleware](examples/plugins_example.py)** - Middleware and exception handling\n4. **[Cookies](examples/cookies_example.py)** - Session management with cookies\n5. **[Configuration](examples/config_example.py)** - Proxy configuration and security\n6. **[File Uploads](examples/file_upload_example.py)** - Handling multipart form data\n7. **[Database Integration](examples/database_example.py)** - Working with databases\n8. **[CORS](examples/cors_example.py)** - Cross-Origin Resource Sharing configuration\n9. **[Token Auth](examples/auth_example.py)** - Token-based authentication\n10. **[Schema Plugin](examples/schema_plugin_example.py)** - Schema validation with the SchemaPlugin\n\n---\n\n## Core Concepts\n\n### 1. Routing\n\nWebSpark's router is powerful and flexible. Use the `path` helper to define routes and add them to your application with `app.add_paths()`.\n\n#### Parameterized Routes\n\nCapture parts of the URL by defining parameters with a colon (`:`).\n\n```python\n# Route for /users/123\npath(\"/users/:id\", view=UserDetailView.as_view())\n\n# Wildcard route (matches /files/path/to/your/file.txt)\npath(\"/files/*path\", view=FileView.as_view())\n```\n\n#### Nested Routes\n\nOrganize your routes by nesting `path` objects. The parent path's pattern is automatically prefixed to its children.\n\n```python\napp.add_paths([\n    path(\"/api/v1\", children=[\n        path(\"/users\", view=UsersView.as_view()),\n        path(\"/posts\", view=PostsView.as_view()),\n    ])\n])\n# Registers /api/v1/users and /api/v1/posts\n```\n\n### 2. Class-Based Views\n\nViews handle the logic for your routes. They are classes that inherit from `webspark.core.views.View`.\n\n-   **Method Dispatch**: Requests are automatically routed to `handle_\u003cmethod\u003e` methods (e.g., `handle_get`, `handle_post`).\n-   **Context Object**: Each handler method receives a `Context` object with all the request details.\n\n```python\nfrom webspark.core import View\nfrom webspark.http import Context\n\nclass UserView(View):\n    def handle_get(self, ctx: Context):\n        \"\"\"Handles GET /users/:id\"\"\"\n        user_id = ctx.path_params.get('id')\n        page = ctx.query_params.get('page', 1) # Access query params with a default\n\n        ctx.json({\"user_id\": user_id, \"page\": page})\n\n    def handle_post(self, ctx):\n        \"\"\"Handles POST /users\"\"\"\n        data = ctx.body # Access parsed JSON body\n        # ... create a new user ...\n        ctx.json({\"created\": True, \"data\": data}, status=201)\n```\n\n### 3. Schema Validation\n\nEnsure your incoming data is valid by defining schemas. If validation fails, WebSpark automatically returns a `400 Bad Request` response.\n\nDefine a schema by inheriting from `Schema` and adding fields.\n\n```python\nfrom webspark.validation import Schema, StringField, IntegerField, EmailField\n\nclass UserSchema(Schema):\n    name = StringField(required=True, max_length=100)\n    age = IntegerField(min_value=18)\n    email = EmailField(required=True)\n\n\nclass CreateUserView(View):\n\n    def handle_post(self, ctx: Context):\n        # This method is only called if the body is valid.\n        # Access the validated data:\n\n        schema_instance = UserSchema(data=ctx.body)\n\n        if not schema_instance.is_valid():\n            raise HTTPException(\"Validation error.\", schema_instance.errors, status_code=400)\n\n        # ... process the data ...\n        ctx.json({\"user\": schema_instance.validated_data})\n```\n\n#### Available Fields\n\nWebSpark offers a rich set of fields for comprehensive validation:\n\n- `StringField` - String validation with min/max length\n- `IntegerField` - Integer validation with min/max value\n- `FloatField` - Float validation with min/max value\n- `BooleanField` - Boolean value validation\n- `ListField` - List validation with item type specification\n- `SerializerField` - Nested object validation\n- `DateTimeField` - ISO format datetime validation\n- `UUIDField` - UUID validation\n- `EmailField` - Email format validation\n- `URLField` - URL format validation\n- `EnumField` - Enumeration value validation\n- `DecimalField` - Decimal number validation\n- `MethodField` - Custom validation method\n- `RegexField` - Regular expression validation\n\n### 4. Responses\n\nWebSpark provides convenient `Context` that simplifies request handling and response generation.\n\n```python\nfrom webspark.http import Context\n\n# JSON response (most common for APIs)\nctx.json({\"message\": \"Success\"})\n\n# HTML response\nctx.html(\"\u003ch1\u003eHello, World!\u003c/h1\u003e\")\n\n# Plain text response\nctx.text(\"OK\")\n\n# Stream a large file without loading it all into memory\nctx.stream(\"/path/to/large/video.mp4\")\n\n# Redirect response\nctx.redirect(\"/new-url\")\n```\n\n### 5. Cookies\n\nEasily set and delete cookies on the `Context` object.\n\n```python\nclass AuthView(View):\n    def handle_post(self, ctx: Context):\n        # Set a cookie on login\n        ctx.set_cookie(\"session_id\", \"abc123\", path=\"/\", max_age=3600, httponly=True, secure=True)\n        ctx.json({\"logged_in\": True})\n\n    def handle_delete(self, ctx: Context):\n        # Delete a cookie on logout\n        ctx.delete_cookie(\"session_id\")\n        ctx.json({\"logged_out\": True})\n```\n\n### 6. Middleware (Plugins)\n\nPlugins allow you to hook into the request-response lifecycle. A plugin is a class that implements an `apply` method, which wraps a view handler.\n\nHere is a simple logging plugin:\n\n```python\nfrom webspark.core import Plugin\n\nclass LoggingPlugin(Plugin):\n    def apply(self, handler):\n        # This method returns a new handler that wraps the original one.\n        def wrapped_handler(ctx):\n            print(f\"Request: {ctx.method} {ctx.path}\")\n            handler(ctx) # The original view handler is called here\n            print(f\"Response: {ctx.status}\")\n        return wrapped_handler\n\n# Register the plugin globally\napp = WebSpark(plugins=[LoggingPlugin()])\n\n# Or apply it to a specific path\napp.add_paths([\n    path(\"/admin\", view=AdminView.as_view(), plugins=[AuthPlugin()])\n])\n```\n\n#### CORS Plugin\n\nWebSpark includes a CORS (Cross-Origin Resource Sharing) plugin that implements the full CORS specification. It supports both simple and preflighted requests with configurable origins, methods, headers, and credentials.\n\n```python\nfrom webspark.contrib.plugins import CORSPlugin\n\n# Create a CORS plugin with a specific configuration\ncors_plugin = CORSPlugin(\n    allow_origins=[\"https://mydomain.com\", \"https://api.mydomain.com\"],\n    allow_methods=[\"GET\", \"POST\", \"PUT\", \"DELETE\"],\n    allow_headers=[\"Content-Type\", \"Authorization\", \"X-Requested-With\"],\n    allow_credentials=True,\n    max_age=86400,  # 24 hours\n    expose_headers=[\"X-Custom-Header\"]\n)\n\n# Register the plugin globally\napp = WebSpark(plugins=[cors_plugin])\n\n# Or apply it to specific paths\napp.add_paths([\n    path(\"/api/\", view=APIView.as_view(), plugins=[cors_plugin])\n])\n```\n\nThe CORS plugin supports the following configuration options:\n\n- `allow_origins` - List of allowed origins. Use `[\"*\"]` to allow all origins (not recommended for production with credentials).\n- `allow_methods` - List of allowed HTTP methods.\n- `allow_headers` - List of allowed headers.\n- `allow_credentials` - Whether to allow credentials (cookies, authorization headers).\n- `max_age` - How long the preflight response should be cached (in seconds).\n- `expose_headers` - List of headers that browsers are allowed to access.\n- `vary_header` - Whether to add Vary header for preflight requests.\n\n#### AllowedHosts Plugin\n\nTo prevent HTTP Host header attacks, WebSpark provides an `AllowedHostsPlugin`. This plugin checks the request's `Host` header against a list of allowed hostnames.\n\n```python\nfrom webspark.contrib.plugins import AllowedHostsPlugin\n\n# Allow requests only to \"mydomain.com\" and any subdomain of \"api.mydomain.com\"\nallowed_hosts_plugin = AllowedHostsPlugin(\n    allowed_hosts=[\"mydomain.com\", \".api.mydomain.com\"]\n)\n\n# Register the plugin globally\napp = WebSpark(plugins=[allowed_hosts_plugin])\n```\n\n-   **Behavior**:\n    -   If `allowed_hosts` is not set, all requests will be rejected with a `400 Bad Request` error, ensuring that only requests from specified hosts are processed.\n-   **Matching**:\n    -   `\"mydomain.com\"`: Matches the exact domain.\n    -   `\".mydomain.com\"`: Matches `mydomain.com` and any subdomain (e.g., `api.mydomain.com`).\n    -   `\"*\"`: Matches any host.\n\n#### TokenAuth Plugin\n\nWebSpark provides a `TokenAuthPlugin` for implementing token-based authentication, typically used for APIs.\nThis plugin can check for a token either in the **Authorization header** or in a **cookie**, and then validates it using a provided function.\n\n```python\nfrom webspark.contrib.plugins import TokenAuthPlugin\n\n# A simple function to validate a token and return a user object.\n# In a real application, this would check a database or cache.\ndef get_user_from_token(token: str):\n    if token == \"secret-token\":\n        return {\"username\": \"admin\"}\n    return None\n\n# Create a token auth plugin (header-based by default)\ntoken_auth_plugin = TokenAuthPlugin(token_loader=get_user_from_token)\n\n# Or configure it to read from a cookie instead:\ncookie_auth_plugin = TokenAuthPlugin(\n    token_loader=get_user_from_token,\n    cookie_name=\"auth_token\",   # will look for Cookie: auth_token=\u003ctoken\u003e\n)\n\n# Apply the plugin to a protected view\napp.add_paths([\n    path(\"/protected\", view=ProtectedView.as_view(), plugins=[token_auth_plugin])\n])\n```\n\n-   **Behavior**:\n    -   By default, the plugin expects an **Authorization** header in the format `Authorization: Token \u003cyour-token\u003e`, the scheme (`Token`) can be customized when instantiating the plugin.\n    -   If `cookie_name` is provided, the plugin will first check for a cookie with that name `Cookie: auth_token=\u003cyour-token\u003e`, if not found, it falls back to the Authorization header.\n    -   If no valid token is found, the plugin returns a `401 Unauthorized` response with a `WWW-Authenticate` header.\n    -   If the token is successfully validated by the `token_loader` function, the returned user object is attached to the context as `ctx.state[\"user\"]` and the request proceeds to the view.\n\n#### Schema Validation Plugin\n\nWebSpark provides a `SchemaPlugin` for validating data from the request context using an `Schema`. This plugin can validate any data accessible through the context object, such as the request body, query parameters, or path parameters.\n\nThe plugin reads a value from the view context using `prop`. If that value is callable, it raises `ValueError`. The data is then validated using the provided `schema`. If validation succeeds, the validated data is injected into the handler's keyword arguments. If validation fails, an `HTTPException` with status code 400 is raised.\n\nYou can apply the SchemaPlugin using the `@apply` decorator from `webspark.utils.decorators`:\n\n```python\nfrom webspark.contrib.plugins import SchemaPlugin\nfrom webspark.core import View\nfrom webspark.http import Context\nfrom webspark.validation import Schema, StringField, IntegerField\nfrom webspark.utils import apply\n\n# Define a schema for validation\nclass UserSchema(Schema):\n    name = StringField(required=True, max_length=100)\n    age = IntegerField(min_value=1, max_value=120)\n\nclass UserView(View):\n    @apply(\n        SchemaPlugin(UserSchema, prop=\"body\", param=\"validated_body\"),\n    )\n    def handle_post(self, ctx: Context, validated_body: dict):\n        # The validated_body parameter contains the validated data\n        ctx.json({\"received\": validated_body}, status=201)\n```\n\nIn this example:\n- `prop=\"body\"` tells the plugin to read data from `ctx.body`\n- `param=\"validated_body\"` specifies that the validated data should be passed to the handler as the `validated_body` keyword argument\n- If validation fails, an HTTP 400 error is automatically returned with details about the validation errors\n\nYou can also apply the plugin to a specific path when registering routes:\n\n```python\napp.add_paths([\n    path(\"/users\", view=UserView.as_view(), plugins=[\n        SchemaPlugin(UserSchema, prop=\"body\", param=\"validated_body\")\n    ])\n])\n```\n\n#### The `apply` Helper\n\nWebSpark provides an `apply` helper function in `webspark.utils.decorators` that makes it easy to apply plugins directly to view methods. This is particularly useful for applying plugins to specific handlers rather than entire views or routes.\n\nThe `apply` function takes one or more plugin instances and returns a decorator that wraps the target function with those plugins:\n\n```python\nfrom webspark.utils import apply\nfrom webspark.contrib.plugins import SchemaPlugin, CORSPlugin\n\n# Apply a single plugin\n@apply(SchemaPlugin(UserSchema, prop=\"body\"))\ndef handle_post(self, ctx: Context, body: dict):\n    # Handler logic here\n    pass\n\n# Apply multiple plugins\n@apply(\n    CORSPlugin(allow_origins=[\"https://mydomain.com\"]),\n    SchemaPlugin(UserSchema, prop=\"body\")\n)\ndef handle_post(self, ctx: Context, body: dict):\n    # Handler logic here\n    pass\n```\n\nThe `apply` helper is especially useful when you want to:\n- Apply validation to specific handlers rather than entire views\n- Combine multiple plugins on a single method\n- Keep plugin configuration close to the code it affects\n\nWhen using `apply`, the plugins are applied in the order they are passed to the function, with the first plugin wrapping the original function, the second plugin wrapping the first, and so on.\n```\n\n### 7. Error Handling\n\nGracefully handle errors using `HTTPException`. When raised, the framework will catch it and generate a standardized JSON error response.\n\n```python\nfrom webspark.utils import HTTPException\n\nclass UserView(View):\n    def handle_get(self, ctx):\n        user_id = ctx.path_params.get('id')\n        user = find_user_by_id(user_id) # Your database logic\n\n        if not user:\n            # This will generate a 404 Not Found response\n            raise HTTPException(\"User not found\", status_code=404)\n\n        ctx.json({\"user\": user.serialize()})\n```\n\n### 8. Custom Exception Handlers\n\nWebSpark allows you to define custom handlers for specific HTTP status codes using the `@app.handle_exception(status_code)` decorator. This is useful for overriding the default JSON error response and providing custom error pages or formats.\n\nThe handler function receives the `request` and the `exception` object and must return a `Response` object.\n\n```python\nfrom webspark.http import Context\n\napp = WebSpark(debug=True)\n\n@app.handle_exception(404)\ndef handle_not_found(ctx: Context, exc: Exception):\n    \"\"\"Custom handler for 404 Not Found errors.\"\"\"\n    ctx.html(\"\u003ch1\u003eOops! Page not found.\u003c/h1\u003e\", status=404)\n\n@app.handle_exception(500)\ndef handle_server_error(ctx: Context, exc: Exception):\n    \"\"\"Custom handler for 500 Internal Server Error.\"\"\"\n    if app.debug:\n        # In debug mode, show the full exception\n        ctx.text(str(exc), status=500)\n    else:\n      ctx.html(\"\u003ch1\u003eA server error occurred.\u003c/h1\u003e\", status=500)\n```\n\n### 9. Proxy Configuration\n\nIf your WebSpark application is running behind a reverse proxy (like Nginx or a load balancer), you'll need to configure it to correctly handle headers like `X-Forwarded-For` and `X-Forwarded-Proto`. This ensures that `request.ip`, `request.scheme`, and `request.host` reflect the original client information, not the proxy's.\n\nProxy support is configured on the `WebSpark` application instance via a configuration object.\n\n```python\nclass AppConfig:\n    TRUST_PROXY = True\n    # For more granular control, you can also specify:\n    # TRUSTED_PROXY_LIST = [\"192.168.1.1\", \"10.0.0.1\"] # List of trusted proxy IPs\n    # TRUSTED_PROXY_COUNT = 1 # Number of trusted proxies in the chain\n\napp = WebSpark(config=AppConfig())\n```\n\n-   **`TRUST_PROXY`**: (bool) Set to `True` to enable proxy header processing. Defaults to `False`.\n-   **`TRUSTED_PROXY_LIST`**: (list) A list of trusted proxy IP addresses. If set, only requests from these IPs will have their proxy headers processed.\n-   **`TRUSTED_PROXY_COUNT`**: (int) The number of reverse proxies that are trusted in the chain. This is useful when you have a known number of proxies.\n\nThe framework checks for the following headers when `TRUST_PROXY` is enabled:\n-   `X-Forwarded-For` and `X-Real-IP` for the client's IP address.\n-   `X-Forwarded-Proto` for the request scheme (`http` or `https`).\n-   `X-Forwarded-Host` for the original host.\n\n### 10. Environment Variable Helper\n\nWebSpark includes a convenient `env` helper function in `webspark.utils` to simplify reading and parsing environment variables.\n\n```python\nfrom webspark.utils import env\n\n# Get a string value with a default\nDATABASE_URL = env(\"DATABASE_URL\", default=\"sqlite:///default.db\")\n\n# Get an integer, raising an error if not set\nPORT = env(\"PORT\", parser=int, raise_exception=True)\n\n# Get a boolean value (handles \"true\", \"1\", \"yes\", \"on\")\nDEBUG = env(\"DEBUG\", default=False, parser=bool)\n```\n\nThis helper streamlines configuration management, making it easy to handle different data types and required settings.\n\n### 11. File Uploads\n\nWebSpark makes handling file uploads simple with built-in multipart form data parsing. Uploaded files are accessible through the `ctx.files` attribute.\n\n```python\nclass FileUploadView(View):\n    def handle_post(self, ctx: Context):\n        # Check if request has files\n        if not ctx.files:\n            raise HTTPException(\"No files uploaded\", status_code=400)\n\n        # Process each uploaded file\n        for field_name, file_list in ctx.files.items():\n            # file_list can be a single file dict or list of file dicts\n            files = file_list if isinstance(file_list, list) else [file_list]\n\n            for file_info in files:\n                # file_info contains:\n                # - filename: original filename\n                # - content_type: MIME type\n                # - file: file-like object with read() method\n\n                # Save the file\n                with open(f\"/uploads/{file_info['filename']}\", \"wb\") as f:\n                    f.write(file_info[\"file\"].read())\n```\n\n---\n\n## Development\n\n### Running Tests\n\nThis project uses `pdm` and `pytest`.\n\n```bash\n# Run all tests\npdm run pytest\n\n# Run tests with coverage\npdm run tests\n```\n\n### Code Quality\n\nWe use `ruff` for linting and formatting.\n\n```bash\n# Check for linting errors\npdm run ruff check .\n\n# Format the code\npdm run ruff format .\n```\n\n---\n\n## Project Structure\n\n```\nwebspark/\n├── core/          # Core components (WSGI app, router, views, schemas)\n├── contrib/       # Optional plugins (CORS, AllowedHosts)\n├── http/          # HTTP abstractions (request, response, cookies)\n├── schema/        # Data validation schemas and fields\n├── utils/         # Utilities (exceptions, JSON handling, env vars)\n├── examples/      # Comprehensive usage examples\n├── tests/         # Test suite for all components\n├── constants.py   # HTTP constants and error codes\n└── __init__.py    # Package metadata\n```\n\n### Core Modules\n\n- **core/** - Contains the fundamental building blocks:\n  - `WebSpark` - The main WSGI application class\n  - `View` - Base class for request handlers\n  - `path` - Routing helper function\n  - `Plugin` - Base class for middleware\n\n- **contrib/plugins/** - Optional plugins:\n  - `CORSPlugin` - Handles Cross-Origin Resource Sharing.\n  - `AllowedHostsPlugin` - Validates incoming Host headers.\n  - `TokenAuthPlugin` - Token-based authentication middleware for securing endpoints.\n  - `SchemaPlugin` - Validates data from the request context using Schema.\n\n- **http/** - HTTP abstractions:\n  - `Context` - Request/response context object\n  - `Cookie` - Cookie handling utilities\n  - `multipart` - File upload handling\n\n- **schema/** - Data validation:\n  - `Schema` - Base class for validation schemas\n  - `fields` - Validation field types\n\n- **utils/** - Utility functions:\n  - `HTTPException` - Standardized error handling\n  - `env` - Environment variable helper\n  - `json` - Optimized JSON handling\n  - `decorators` - Helper decorators including `apply` and `cached_property`\n\n## Contributing\n\nContributions are welcome! Please feel free to fork the repository, make your changes, and submit a pull request.\n\n1.  Fork the repository.\n2.  Create your feature branch (`git checkout -b feature/AmazingFeature`).\n3.  Commit your changes (`git commit -m 'Add some AmazingFeature'`).\n4.  Push to the branch (`git push origin feature/AmazingFeature`).\n5.  Open a pull request.\n\nPlease ensure your code follows the project's style guidelines and includes appropriate tests.\n\n## License\n\nThis project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flsfratel%2Fwebspark","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flsfratel%2Fwebspark","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flsfratel%2Fwebspark/lists"}