Skip to main content

asgi_Statik is a high-performance, plug-and-play static file server for ASGI applications. Built for speed and simplicity, it seamlessly serves assets like HTML, CSS, JS, images, and more—without external dependencies or bulky middleware. Designed to fit naturally into async Python frameworks like Nexios, Statik gives you fine-grained control over file serving, cache headers, and MIME types—while keeping your stack minimal.

Project description

Statik

Statik

A minimalist, high-performance static file server for ASGI applications.

Python Version License: MIT

Overview

Statik is a high-performance static file server designed for ASGI applications. It provides efficient file serving capabilities with minimal dependencies, making it ideal for production environments where performance and security are critical.

Core Features

  • High Performance: Optimized for serving static files with minimal overhead and maximum throughput
  • Minimal Dependencies: Core functionality requires only anyio and typing-extensions
  • Security Features: Built-in protection against path traversal and configurable authentication
  • Compression Support: Automatic gzip and deflate compression for supported content types
  • Caching System: ETag support and configurable cache control headers
  • Streaming Support: Efficient large file handling with configurable chunk sizes
  • SPA Mode: Built-in Single Page Application support
  • Directory Listings: Optional HTML/JSON directory listings with authentication
  • Range Requests: Support for partial content and resume downloads

Installation

pip install statik

Basic Usage

from statik import StaticFiles

# Basic static file server
app = StaticFiles(directory="static")

# Run with any ASGI server
# Example with uvicorn:
# uvicorn myapp:app

Configuration Guide

Basic Configuration

from statik import StaticFiles, StaticFilesConfig

# Simple static file server
app = StaticFiles(directory="static")

# Advanced configuration
config = StaticFilesConfig(
    directory="static",
    chunk_size=32 * 1024,  # 32KB chunks
    follow_symlinks=False,
    check_dir=True
)
app = StaticFiles(config=config)

Security Configuration

config = StaticFilesConfig(
    directory="static",
    allowed_methods=["GET", "HEAD"],
    directory_listing_auth={
        "admin": "secret"  # Basic auth for directory listing
    },
    follow_symlinks=False,
    check_dir=True
)

Caching and Compression

config = StaticFilesConfig(
    directory="static",
    enable_compression=True,
    compression_min_size=1024,  # 1KB minimum
    compression_types=[
        "text/",
        "application/javascript",
        "application/json",
        "application/xml"
    ],
    cache_control="public, max-age=3600",
    cache_max_age=3600
)

Single Page Application (SPA) Configuration

config = StaticFilesConfig(
    directory="static",
    spa_mode=True,
    index_files=["index.html"],
    cache_control="public, max-age=3600"
)

Framework Integration

FastAPI Integration

from fastapi import FastAPI
from statik import StaticFiles, StaticFilesConfig

app = FastAPI()

# Basic static files
app.mount("/static", StaticFiles(directory="static"))

# Advanced configuration
config = StaticFilesConfig(
    directory="static/assets",
    enable_compression=True,
    compression_min_size=1024,
    cache_control="public, max-age=3600",
    spa_mode=False
)

# Mount multiple static directories
app.mount("/assets", StaticFiles(config=config))
app.mount("/public", StaticFiles(directory="public"))

# Protected static files with basic auth
protected_config = StaticFilesConfig(
    directory="protected",
    directory_listing_auth={
        "admin": "secret123"
    },
    allow_directory_listing=True
)
app.mount("/protected", StaticFiles(config=protected_config))

# Example route using static files
@app.get("/")
async def read_root():
    return {"message": "Static files are served at /static, /assets, and /protected"}

Starlette Integration

from starlette.applications import Starlette
from starlette.routing import Mount
from starlette.responses import JSONResponse
from statik import StaticFiles, StaticFilesConfig

routes = [
    # Basic static files
    Mount("/static", StaticFiles(directory="static")),
    
    # SPA configuration
    Mount("/app", StaticFiles(
        config=StaticFilesConfig(
            directory="spa",
            spa_mode=True,
            index_files=["index.html"],
            cache_control="public, max-age=3600"
        )
    )),
    
    # Media files with compression
    Mount("/media", StaticFiles(
        config=StaticFilesConfig(
            directory="media",
            enable_compression=True,
            compression_types=[
                "image/svg+xml",
                "application/json",
                "text/css",
                "application/javascript"
            ]
        )
    ))
]

app = Starlette(routes=routes)

@app.route("/")
async def homepage(request):
    return JSONResponse({
        "static_routes": [
            "/static",
            "/app",
            "/media"
        ]
    })

Nexios Integration

from nexios import NexiosApp
from statik import StaticFiles, StaticFilesConfig

app = NexiosApp()

# Basic static file serving
app.register(StaticFiles(directory="static"),"/static")



@app.get("/api/status")
async def status(req, res):
    return {
        "status": "running",
        "static_mounts": [
            "/",  # SPA
            "/docs",
            "/media"
        ]
    }

# Run the application
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Common Integration Patterns

Serving Multiple Directories

from fastapi import FastAPI
from statik import StaticFiles, StaticFilesConfig

app = FastAPI()

# Structure:
# /static
#   /css
#   /js
#   /images
# /uploads
# /public

# Serve different directories with different configurations
app.mount("/static", StaticFiles(
    config=StaticFilesConfig(
        directory="static",
        enable_compression=True,
        cache_control="public, max-age=3600"
    )
))

app.mount("/uploads", StaticFiles(
    config=StaticFilesConfig(
        directory="uploads",
        chunk_size=256 * 1024,  # Larger chunks for uploads
        enable_compression=False  # Don't compress already compressed files
    )
))

app.mount("/public", StaticFiles(directory="public"))

SPA with API Backend

from fastapi import FastAPI
from statik import StaticFiles, StaticFilesConfig

app = FastAPI()

# Serve SPA from /app
spa_config = StaticFilesConfig(
    directory="frontend/dist",
    spa_mode=True,
    enable_compression=True,
    cache_control="public, max-age=3600"
)
app.mount("/app", StaticFiles(config=spa_config))

# API routes
@app.get("/api/data")
async def get_data():
    return {"data": "example"}

# Serve API documentation
docs_config = StaticFilesConfig(
    directory="docs",
    allow_directory_listing=True
)
app.mount("/docs", StaticFiles(config=docs_config))

Protected Media Server

from fastapi import FastAPI
from statik import StaticFiles, StaticFilesConfig

app = FastAPI()

# Protected media files with authentication
media_config = StaticFilesConfig(
    directory="media",
    directory_listing_auth={
        "admin": "secure_password",
        "user": "user_password"
    },
    allow_directory_listing=True,
    chunk_size=128 * 1024,
    compression_types=[
        "image/svg+xml",
        "text/plain",
        "application/json"
    ]
)

app.mount("/media", StaticFiles(config=media_config))

# Optional: Add route to check auth status
@app.get("/media-status")
async def media_status():
    return {
        "status": "available",
        "auth_required": True
    }

These examples demonstrate common use cases and best practices for integrating Statik with various frameworks. Each example includes appropriate configuration for the specific use case, such as:

  • Compression settings for appropriate file types
  • Caching strategies
  • Authentication for protected resources
  • SPA mode configuration
  • Large file handling
  • Multiple directory mounting

Choose and adapt these examples based on your specific requirements.

Configuration Reference

StaticFilesConfig Options

Option Type Default Description
directory str|Path Required Base directory for serving files
check_dir bool True Verify directory exists on startup
follow_symlinks bool False Allow following symbolic links
allow_directory_listing bool False Enable directory listing feature
directory_listing_auth dict None Basic auth credentials for directory listing
allowed_methods list ["GET", "HEAD"] Allowed HTTP methods
cache_control str None Cache-Control header value
cache_max_age int 3600 Cache max age in seconds
enable_compression bool False Enable compression support
compression_min_size int 1024 Minimum file size for compression
compression_types list See below MIME types to compress
chunk_size int 64 * 1024 File streaming chunk size
spa_mode bool False Enable SPA mode
index_files list ["index.html"] List of index file names

Default Compression Types

DEFAULT_COMPRESSION_TYPES = [
    "text/",
    "application/javascript",
    "application/json",
    "application/xml",
    "application/wasm"
]

Performance Optimization

Chunk Size Configuration

  • Larger chunks (128KB+): Better for high-bandwidth scenarios
  • Smaller chunks (32KB): Better for memory-constrained environments
  • Default (64KB): Good balance for most use cases
config = StaticFilesConfig(
    directory="static",
    chunk_size=128 * 1024  # 128KB chunks
)

Compression Guidelines

  1. Enable compression only for text-based files
  2. Set appropriate minimum file size (typically 1KB+)
  3. Configure supported MIME types carefully

Caching Strategy

  1. Set appropriate cache-control headers
  2. Enable ETag support for client-side caching
  3. Configure cache max age based on content update frequency

Security Best Practices

  1. Keep follow_symlinks=False unless specifically needed
  2. Implement authentication for sensitive directories
  3. Use allowed_methods to restrict HTTP methods
  4. Validate file paths against directory traversal

Error Handling

The server handles various error conditions with appropriate HTTP status codes:

  • 404 Not Found: File or directory not found
  • 403 Forbidden: Access denied or directory traversal attempt
  • 401 Unauthorized: Failed authentication
  • 405 Method Not Allowed: Invalid HTTP method
  • 500 Internal Server Error: Unexpected server errors

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/improvement)
  3. Commit your changes (git commit -am 'Add new feature')
  4. Push to the branch (git push origin feature/improvement)
  5. Create a Pull Request

For major changes, please open an issue first to discuss the proposed changes.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

asgi_statik-0.1.0.tar.gz (17.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

asgi_statik-0.1.0-py3-none-any.whl (19.4 kB view details)

Uploaded Python 3

File details

Details for the file asgi_statik-0.1.0.tar.gz.

File metadata

  • Download URL: asgi_statik-0.1.0.tar.gz
  • Upload date:
  • Size: 17.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.11.12 Linux/6.11.0-1015-azure

File hashes

Hashes for asgi_statik-0.1.0.tar.gz
Algorithm Hash digest
SHA256 29cd99e7a4b7a16afcdc1b5aead687900adb91d314279f1851adcfbcf3ae3d37
MD5 6d4f4ca9a59dbfd3c2843765a85e90ea
BLAKE2b-256 b20048755eda913c754945fa7522a1bddf5a47088fa3c5631ae8c4500bc70500

See more details on using hashes here.

File details

Details for the file asgi_statik-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: asgi_statik-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.11.12 Linux/6.11.0-1015-azure

File hashes

Hashes for asgi_statik-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b9cf5bde9be1692a8d9918b8ee4cab4b98d03868af837768477ce4d4e5bf42d8
MD5 fa1b01542a11fd467462d16d33d38586
BLAKE2b-256 7b72e15e66cc3da0061bbc11cb37efb5892f3ec39461dae9dbd970b4c4a6f01e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page