Thanks to visit codestin.com
Credit goes to lib.rs

#view #dto #patch #api #serde

model-views

Type-safe view types for different access modes (Get, Create, Patch) on data models

2 releases

Uses new Rust 2024

0.1.1 Nov 14, 2025
0.1.0 Nov 14, 2025

#644 in Encoding

EUPL-1.2

20KB
186 lines

model-views

Crates.io Documentation License: EUPL-1.2 Rust Version

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.

Key Features

  • Type Safety: Different operations use different types, catching errors at compile time
  • Reduced Boilerplate: Automatically generates DTOs from model definitions
  • Explicit Updates: Patch<T> type makes update intent clear
  • Serde Integration: Optional serialization/deserialization support
  • Nested Models: Works seamlessly with nested structures
  • Generic Support: Handles generic types and where clauses

Usage

Add this to your Cargo.toml:

[dependencies]
model-views = "0.1"

Basic Example

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("[email protected]".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
};

Field Policies

Control field visibility in each view mode:

Get Mode

  • get = "required" - Field is always present (default)
  • get = "optional" - Field is wrapped in Option<T>
  • get = "forbidden" - Field is excluded

Create Mode

  • create = "required" - Field must be provided (default)
  • create = "optional" - Field is wrapped in Option<T>
  • create = "forbidden" - Field is excluded

Patch Mode

  • patch = "required" - Field is wrapped in Patch<T> (default)
  • patch = "optional" - Field is wrapped in Patch<Option<T>>
  • patch = "forbidden" - Field is excluded

Nested Models

#[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 Type

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();

Cargo Features

The following cargo features are available:

  • derive (default) - Enables the #[derive(Views)] macro
  • serde - Adds Serialize/Deserialize support for Patch<T>
  • uuid - Implements View for uuid::Uuid
  • chrono - Implements View for chrono::DateTime<Utc>

Use Cases

This library is particularly useful for:

  • REST API request/response types
  • GraphQL input/output types
  • Database model transformations
  • Form validation and submission
  • Any scenario where different operations require different field sets

License

Licensed under the European Union Public Licence (EUPL), Version 1.2.

Dependencies

~0.2–0.9MB
~16K SLoC