Type-safe view types for different access modes on data models.
This crate provides a trait-based system for generating specialized view types for different operations on data models (Get/Read, Create, Patch/Update). Each view type only includes the fields relevant to that operation, enforcing API contracts at compile time.
Core Concepts
View Modes
The crate defines three access modes for models:
- [
ViewModeGet]: For read operations, retrieving existing data - [
ViewModeCreate]: For create operations, accepting input to create new entities - [
ViewModePatch]: For update operations, allowing partial modifications
The View Trait
The [View] trait associates a type with its representation in a specific mode:
This allows the same model to have different representations depending on the operation.
Patch Type
The [Patch<T>] enum is central to update operations, providing an explicit way to
distinguish between "don't update this field" and "update this field to a value":
Patch::Ignore: Leave the field unchangedPatch::Update(value): Update the field to the given value
This is clearer than using Option<T> for updates, especially when dealing with
optional fields.
Usage
Basic Example
use ;
// This generates three types:
// UserGet - for reading user data
let user_get = UserGet ;
// UserCreate - for creating new users
let user_create = UserCreate ;
// UserPatch - for updating users
let user_patch = UserPatch ;
Nested Models
Views work seamlessly with nested structures:
# use ;
#
#
#
// PostPatch will have: author: Patch<Option<UserPatch>>
let post_patch = PostPatch ;
Field Policies
Each field can be configured independently for each view mode:
-
get = "required": Field is always present in Get view -
get = "optional": Field isOption<T>in Get view -
get = "forbidden": Field is excluded from Get view -
create = "required": Field must be provided when creating -
create = "optional": Field isOption<T>in Create view -
create = "forbidden": Field cannot be set during creation -
patch = "patch": Field isPatch<T>in Patch view -
patch = "optional": Field isPatch<Option<T>>in Patch view -
patch = "forbidden": Field cannot be modified via patches
Features
derive(default): Enables the#[derive(Views)]procedural macroserde: AddsSerialize/Deserializesupport forPatch<T>uuid: ImplementsViewforuuid::Uuidchrono: ImplementsViewforchrono::DateTime<Utc>
Benefits
- Type Safety: Different operations use different types, catching errors at compile time
- API Clarity: View types clearly document which fields are required/optional for each operation
- Reduced Boilerplate: Automatically generates DTOs (Data Transfer Objects) from models
- Explicit Updates:
Patch<T>makes update intent clear, avoiding ambiguity withOption<T>