Skip to main content

modo_upload/
lib.rs

1//! File upload support for modo applications.
2//!
3//! Provides multipart form parsing, in-memory buffering, pluggable storage
4//! backends, and file validation.  The `#[derive(FromMultipart)]`
5//! macro generates the boilerplate for mapping multipart fields to struct fields.
6//!
7//! # Features
8//!
9//! - `local` (default) — local filesystem storage via [`storage::local::LocalStorage`].
10//! - `opendal` — S3-compatible object storage via `storage::opendal::OpendalStorage`
11//!   and the `S3Config` configuration type.
12//!
13//! # Quick start
14//!
15//! Define a form struct, register the storage backend as a service, then
16//! extract the form in a handler:
17//!
18//! ```rust,ignore
19//! use std::sync::Arc;
20//! use modo::{AppConfig, Json, JsonResult, Service};
21//! use modo_upload::{FileStorageDyn, FromMultipart, MultipartForm, UploadConfig, UploadedFile, storage};
22//! use serde::Deserialize;
23//!
24//! #[derive(Default, Deserialize)]
25//! struct AppSettings {
26//!     #[serde(flatten)]
27//!     core: AppConfig,
28//!     #[serde(default)]
29//!     upload: UploadConfig,
30//! }
31//!
32//! #[derive(FromMultipart)]
33//! struct UploadForm {
34//!     #[upload(max_size = "5mb", accept = "image/*")]
35//!     avatar: UploadedFile,
36//!     name: String,
37//! }
38//!
39//! #[modo::handler(POST, "/upload")]
40//! async fn upload(
41//!     file_storage: Service<Arc<dyn FileStorageDyn>>,
42//!     form: MultipartForm<UploadForm>,
43//! ) -> JsonResult<()> {
44//!     let stored = file_storage.store("avatars", &form.avatar).await?;
45//!     println!("stored at {}", stored.path);
46//!     Ok(Json(()))
47//! }
48//!
49//! #[modo::main]
50//! async fn main(
51//!     app: modo::app::AppBuilder,
52//!     config: AppSettings,
53//! ) -> Result<(), Box<dyn std::error::Error>> {
54//!     let file_storage = storage(&config.upload)?;
55//!     app.config(config.core).service(file_storage).run().await
56//! }
57//! ```
58
59pub use modo_upload_macros::FromMultipart;
60
61mod config;
62mod extractor;
63mod file;
64mod from_multipart;
65pub mod storage;
66mod stream;
67mod validate;
68
69#[cfg(feature = "opendal")]
70pub use config::S3Config;
71pub use config::{StorageBackend, UploadConfig};
72pub use extractor::MultipartForm;
73pub use file::UploadedFile;
74pub use from_multipart::FromMultipart;
75pub use storage::{FileStorage, FileStorageDyn, FileStorageSend, StoredFile, storage};
76pub use stream::BufferedUpload;
77pub use validate::{gb, kb, mb};
78
79/// Internal helpers exposed for use by generated code. Not public API.
80#[doc(hidden)]
81pub mod __internal {
82    pub use crate::validate::mime_matches;
83    pub use axum;
84}