Storage Plugin¶
The StoragePlugin provides seamless integration with Litestar applications,
handling dependency injection and lifecycle management for storage instances.
Plugin Class¶
- class litestar_storages.contrib.plugin.StoragePlugin[source]¶
Bases:
InitPluginProtocolLitestar plugin for storage integration.
This plugin provides dependency injection support for storage instances, enabling seamless integration with Litestar applications. It supports both single and multiple named storage configurations.
- Provides:
Dependency injection of storage instances
Lifespan management (connection cleanup)
Multiple named storage support
Example
Single storage configuration:
from litestar import Litestar from litestar_storages import S3Storage, S3Config, StoragePlugin storage = S3Storage(config=S3Config(bucket="uploads")) app = Litestar( route_handlers=[...], plugins=[StoragePlugin(storage)], )
Multiple named storages:
from litestar import Litestar from litestar_storages import S3Storage, AzureStorage, StoragePlugin app = Litestar( route_handlers=[...], plugins=[ StoragePlugin( default=S3Storage(config=S3Config(bucket="main-uploads")), images=S3Storage(config=S3Config(bucket="images")), documents=AzureStorage(config=AzureConfig(container="docs")), ) ], )
Using in route handlers:
from litestar import post from litestar.datastructures import UploadFile from litestar_storages import Storage, StoredFile @post("/upload") async def upload( data: UploadFile, storage: Storage, # Injected default storage ) -> StoredFile: return await storage.put( key=f"uploads/{data.filename}", data=data.file, content_type=data.content_type, ) @post("/upload-image") async def upload_image( data: UploadFile, images_storage: Storage, # Injected named storage ) -> StoredFile: return await images_storage.put( key=f"images/{data.filename}", data=data.file, content_type=data.content_type, )
- __init__(default=None, **named_storages)[source]¶
Initialize the StoragePlugin.
- Parameters:
Example:
plugin = StoragePlugin( default=S3Storage(...), images=S3Storage(...), documents=AzureStorage(...), )
- This registers three dependencies:
storage (from default)
images_storage
documents_storage
- on_app_init(app_config)[source]¶
Register storage instances as dependencies on application initialization.
This method is called by Litestar during application startup. It registers each storage instance as a dependency that can be injected into route handlers.
- Parameters:
app_config (
AppConfig) – The Litestar application configuration- Return type:
- Returns:
Modified application configuration with storage dependencies registered
Note
The “default” storage is registered as “storage”
Named storages are registered as “{name}_storage”
Existing dependencies are preserved
Features¶
Dependency Injection¶
The plugin registers storage instances as dependencies that can be injected into route handlers:
from litestar import Litestar, get, post
from litestar_storages import Storage, StoredFile
from litestar_storages.contrib import StoragePlugin
@post("/upload")
async def upload(
data: bytes,
storage: Storage, # Injected
) -> StoredFile:
return await storage.put("file.txt", data)
@get("/files")
async def list_files(storage: Storage) -> list[StoredFile]:
return [file async for file in storage.list()]
Named Storages¶
Register multiple storages with different names:
plugin = StoragePlugin(
default=s3_storage, # Injected as "storage"
uploads=upload_storage, # Injected as "uploads_storage"
cache=cache_storage, # Injected as "cache_storage"
)
@post("/upload")
async def upload(
storage: Storage, # Default storage
uploads_storage: Storage, # Named storage
) -> StoredFile:
...
Automatic Cleanup¶
The plugin registers a shutdown handler that closes all storage instances:
# On application shutdown, this is called automatically:
for storage in storages.values():
await storage.close()
This ensures proper cleanup of:
HTTP sessions (aioboto3, gcloud-aio-storage, azure-storage-blob)
Connection pools
File handles
Usage Examples¶
Single Storage¶
from litestar import Litestar
from litestar_storages import S3Storage, S3Config
from litestar_storages.contrib import StoragePlugin
storage = S3Storage(
config=S3Config(
bucket="my-uploads",
region="us-east-1",
)
)
app = Litestar(
route_handlers=[...],
plugins=[StoragePlugin(default=storage)],
)
Multiple Storages by Environment¶
import os
from litestar import Litestar
from litestar_storages import (
MemoryStorage,
S3Storage, S3Config,
FileSystemStorage, FileSystemConfig,
)
from litestar_storages.contrib import StoragePlugin
def get_storage():
env = os.getenv("ENV", "development")
if env == "production":
return S3Storage(config=S3Config(
bucket=os.environ["S3_BUCKET"],
region=os.environ["AWS_REGION"],
))
elif env == "staging":
return FileSystemStorage(config=FileSystemConfig(
path=Path("/var/uploads"),
))
else:
return MemoryStorage()
app = Litestar(
route_handlers=[...],
plugins=[StoragePlugin(default=get_storage())],
)
With DTOs¶
from litestar import post
from litestar.datastructures import UploadFile
from litestar_storages import Storage, StoredFile
from litestar_storages.contrib import StoragePlugin, StoredFileDTO
@post("/upload", return_dto=StoredFileDTO)
async def upload(
data: UploadFile,
storage: Storage,
) -> StoredFile:
content = await data.read()
return await storage.put(
key=f"uploads/{data.filename}",
data=content,
content_type=data.content_type,
)
Complete Application¶
from litestar import Litestar, get, post, delete
from litestar.datastructures import UploadFile
from litestar.response import Stream
from litestar_storages import Storage, StoredFile
from litestar_storages.contrib import StoragePlugin, StoredFileDTO
from litestar_storages.exceptions import StorageFileNotFoundError
@post("/files", return_dto=StoredFileDTO)
async def upload_file(
data: UploadFile,
storage: Storage,
) -> StoredFile:
content = await data.read()
return await storage.put(
key=f"files/{data.filename}",
data=content,
content_type=data.content_type,
)
@get("/files/{key:path}")
async def download_file(
key: str,
storage: Storage,
) -> Stream:
async def stream():
async for chunk in storage.get(f"files/{key}"):
yield chunk
return Stream(stream())
@get("/files/{key:path}/info", return_dto=StoredFileDTO)
async def get_file_info(
key: str,
storage: Storage,
) -> StoredFile:
return await storage.info(f"files/{key}")
@delete("/files/{key:path}")
async def delete_file(
key: str,
storage: Storage,
) -> None:
await storage.delete(f"files/{key}")
app = Litestar(
route_handlers=[upload_file, download_file, get_file_info, delete_file],
plugins=[StoragePlugin(default=S3Storage(config=S3Config(bucket="files")))],
)