| Crates.io | model-views-derive |
| lib.rs | model-views-derive |
| version | 0.1.1 |
| created_at | 2025-11-14 14:19:41.579611+00 |
| updated_at | 2025-11-14 14:22:42.719026+00 |
| description | Type-safe view types for different access modes (Get, Create, Patch) on data models |
| homepage | |
| repository | https://github.com/sunsided/model-views |
| max_upload_size | |
| id | 1932958 |
| size | 23,476 |
Type-safe view types for different access modes on data models.
This library automatically generates specialized view types for Get, Create, and Patch operations from your model structs. Each view type only includes the fields relevant to that operation, enforcing API contracts at compile time and reducing boilerplate.
Patch<T> type makes update intent clearAdd this to your Cargo.toml:
[dependencies]
model-views = "0.1"
use model_views::{Views, Patch};
#[derive(Views)]
#[views(serde)]
struct User {
// ID is read-only, generated by the system
#[views(get = "required", create = "forbidden", patch = "forbidden")]
id: u64,
// Name is required for all operations
#[views(get = "required", create = "required", patch = "required")]
name: String,
// Email is optional
#[views(get = "optional", create = "optional", patch = "optional")]
email: Option<String>,
}
// Reading a user
let user = UserGet {
id: 1,
name: "Alice".to_string(),
email: Some("alice@example.com".to_string()),
};
// Creating a new user (no ID field)
let create = UserCreate {
name: "Bob".to_string(),
email: None,
};
// Updating a user (only specify changed fields)
let patch = UserPatch {
name: Patch::Update("Charlie".to_string()),
email: Patch::Ignore, // Don't change email
};
Control field visibility in each view mode:
get = "required" - Field is always present (default)get = "optional" - Field is wrapped in Option<T>get = "forbidden" - Field is excludedcreate = "required" - Field must be provided (default)create = "optional" - Field is wrapped in Option<T>create = "forbidden" - Field is excludedpatch = "required" - Field is wrapped in Patch<T> (default)patch = "optional" - Field is wrapped in Patch<Option<T>>patch = "forbidden" - Field is excluded#[derive(Views)]
struct Article {
#[views(get = "required", create = "forbidden", patch = "forbidden")]
id: u64,
#[views(get = "required", create = "required", patch = "required")]
title: String,
// Nested view types are automatically handled
#[views(get = "required", create = "forbidden", patch = "optional")]
author: User,
}
The Patch<T> enum makes update intent explicit:
use model_views::Patch;
// Explicitly ignore a field
let no_change = Patch::Ignore;
// Update a field to a new value
let update = Patch::Update("new value".to_string());
// Convert to/from Option
let opt: Option<String> = update.into();
let patch: Patch<String> = Some("value".to_string()).into();
The following cargo features are available:
derive (default) - Enables the #[derive(Views)] macroserde - Adds Serialize/Deserialize support for Patch<T>uuid - Implements View for uuid::Uuidchrono - Implements View for chrono::DateTime<Utc>This library is particularly useful for:
Licensed under the European Union Public Licence (EUPL), Version 1.2.