liveBook · Manning

Data model

As explained in Rust Servers, Services, and Apps

A data model is a structured specification of the data entities, fields, and relationships represented by a software system.

A data model gives application data a shape at each boundary: database rows, Rust values, and HTTP payloads. In a course service, a `Course` struct represents the fields read from PostgreSQL and used by handlers. Its fields need to agree with the table columns and their types. section 4.2.2 section 4.3.2

/* Drop table if it already exists*/
drop table if exists ezy_course_c4;
/* Create a table. */
/* Note: Don't put a comma after last field */
create table ezy_course_c4
(
   course_id serial primary key,
   tutor_id INT not null,
   course_name varchar(140) not null,
   posted_time TIMESTAMP default now()
);
 
/* Load seed data for testing */
insert into ezy_course_c4
   (course_id,tutor_id, course_name,posted_time)
values(1, 1, 'First course', '2020-12-17 05:40:00');
insert into ezy_course_c4
   (course_id, tutor_id, course_name,posted_time)
values(2, 1, 'Second course', '2020-12-18 05:45:00');

The initial `ezy_course_c4` table defines a primary key, a tutor ID, a required course name, and a timestamp with a database default. Its seed rows provide data for testing queries. section 4.2.2

Listing 4.2 Data model for the tutor web service
use actix_web::web;
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
 
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Course {                             #1
   pub course_id: i32,
   pub tutor_id: i32,
   pub course_name: String,
   pub posted_time: Option<NaiveDateTime>,
}
impl From<web::Json<Course>> for Course {       #2
   fn from(course: web::Json<Course>) -> Self {
       Course {
           course_id: course.course_id,
           tutor_id: course.tutor_id,
           course_name: course.course_name.clone(),
           posted_time: course.posted_time,
       }
   }
}

In `src/iter2/models.rs`, `Course` uses `i32` IDs, a `String` name, and `Option<NaiveDateTime>` for the timestamp. Serde derives support serialization and deserialization; the `From<web::Json<Course>>` implementation converts an Actix JSON payload into the application struct. section 4.3.2

As the service grows, keep the model aligned with what each operation accepts and returns:

  • Use separate structures for creation and updating when those operations require different fields. `Option<T>` marks optional Rust fields, with corresponding database column definitions. section 6.4
  • Map query results into structs with `sqlx::query_as!` where suitable, or map records manually. Keep database access and handlers in separate modules from model definitions. section 6.4
  • Extend the schema and APIs together: tutor records add tutor models and tables, while foreign-key constraints define the relationship between tutors and courses. Update handlers, database functions, and tests alongside the model. section 6.3 section 6.4
Listing 8.1 Data model
use serde::{Deserialize, Serialize};
 
#[derive(Serialize, Deserialize, Debug)]
pub struct TutorRegisterForm {            #1
    pub username: String,
    pub password: String,
    pub confirmation: String,
    pub name: String,
    pub imageurl: String,
    pub profile: String,
}
 
#[derive(Serialize, Deserialize, Debug)]
pub struct TutorResponse {                #2
    pub tutor_id: i32,
    pub tutor_name: String,
    pub tutor_pic_url: String,
    pub tutor_profile: String,
}
 
#[derive(Serialize, Deserialize, Debug, sqlx::FromRow)]
pub struct User {                         #3
    pub username: String,
    pub tutor_id: Option<i32>,
    pub user_password: String,
}

A registration frontend uses distinct shapes for a submitted form, a tutor response, and a locally stored user. `User` derives `sqlx::FromRow`, while `tutor_id` is optional—one struct need not serve every boundary. section 8.1

How Rust Servers, Services, and Apps covers it

How deep it goes
Works through field definitions, JSON conversion, optional values, row mapping, and model refactoring rather than a general modeling method.
Examples
Uses a seeded course table, a `Course` struct, and separate registration-form, tutor-response, and user structs.
What it assumes
Assumes familiarity with Rust structs and web-service components; sets up PostgreSQL and a `sqlx` connection before database-backed queries.
What you can do after
Build it from scratch: define operation-specific Rust structs and align them with HTTP payloads, PostgreSQL columns, and query results.
How it connects
Connects data models to database schemas, foreign keys, serialization, HTTP handlers, and SQL query mapping.

Also explained in

Compare how 23 books explain data model →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Rust Servers, Services, and Apps. The section links point to the parts of the book it draws on.