Skip to content

API Reference

Health steps module for managing user step count data.

This module provides CRUD operations and data models for user step tracking including daily step counts and data sources.

Exports
  • CRUD: get_health_steps_number, get_all_health_steps_by_user_id, get_health_steps_by_id_and_user_id, get_health_steps_with_pagination, get_health_steps_by_date, create_health_steps, edit_health_steps, delete_health_steps
  • Schemas: HealthStepsBase, HealthStepsCreate, HealthStepsUpdate, HealthStepsRead, HealthStepsListResponse
  • Enums: Source
  • Models: HealthSteps (ORM model)

HealthStepsBase

Bases: BaseModel

Base model for health steps data.

Represents the core attributes of a user's step count record, including the user reference, date of the record, number of steps taken, and the source of the data.

Attributes:

Name Type Description
date date | None

Calendar date of the steps record. Optional field.

steps StrictInt | None

Number of steps taken. Must be a non-negative integer. Optional field.

source Source | None

Source of the steps data (e.g., device, API, manual entry). Optional field.

Configuration
  • from_attributes: Allows model to be populated from ORM objects.
  • extra: Forbids any extra fields not defined in the model.
  • validate_assignment: Validates field values when assigned after model creation.
  • use_enum_values: Uses enum values instead of enum objects in serialization.
Source code in backend/app/health/health_steps/schema.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class HealthStepsBase(BaseModel):
    """
    Base model for health steps data.

    Represents the core attributes of a user's step count record, including the user reference,
    date of the record, number of steps taken, and the source of the data.

    Attributes:
        date (datetime_date | None): Calendar date of the steps record. Optional field.
        steps (StrictInt | None): Number of steps taken. Must be a non-negative integer. Optional field.
        source (Source | None): Source of the steps data (e.g., device, API, manual entry). Optional field.

    Configuration:
        - from_attributes: Allows model to be populated from ORM objects.
        - extra: Forbids any extra fields not defined in the model.
        - validate_assignment: Validates field values when assigned after model creation.
        - use_enum_values: Uses enum values instead of enum objects in serialization.
    """

    date: datetime_date | None = Field(
        default=None, description="Calendar date of the steps"
    )
    steps: StrictInt | None = Field(
        default=None, ge=0, description="Number of steps taken"
    )
    source: Source | None = Field(default=None, description="Source of the steps data")

    model_config = ConfigDict(
        from_attributes=True,
        extra="forbid",
        validate_assignment=True,
        use_enum_values=True,
    )

HealthStepsCreate

Bases: HealthStepsBase

Validator for HealthStepsCreate model that automatically sets the date field.

This validator runs after model initialization to ensure that if no date is provided, it defaults to today's date.

Source code in backend/app/health/health_steps/schema.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class HealthStepsCreate(HealthStepsBase):
    """
    Validator for HealthStepsCreate model that automatically sets the date field.

    This validator runs after model initialization to ensure that if no date
    is provided, it defaults to today's date.
    """

    @model_validator(mode="after")
    def set_default_date(self) -> "HealthStepsCreate":
        """
        Set date to today if not provided.

        Returns:
            The validated model instance with date set.
        """
        if self.date is None:
            self.date = datetime_date.today()
        return self

set_default_date

set_default_date()

Set date to today if not provided.

Returns:

Type Description
HealthStepsCreate

The validated model instance with date set.

Source code in backend/app/health/health_steps/schema.py
60
61
62
63
64
65
66
67
68
69
70
@model_validator(mode="after")
def set_default_date(self) -> "HealthStepsCreate":
    """
    Set date to today if not provided.

    Returns:
        The validated model instance with date set.
    """
    if self.date is None:
        self.date = datetime_date.today()
    return self

HealthStepsListResponse

Bases: BaseModel

Response model for listing health steps records.

Attributes:

Name Type Description
total StrictInt

Total number of steps records for the user.

num_records StrictInt | None

Number of records in this response.

page_number StrictInt | None

Current page number.

records list[HealthStepsRead]

List of health steps records.

Source code in backend/app/health/health_steps/schema.py
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
class HealthStepsListResponse(BaseModel):
    """
    Response model for listing health steps records.

    Attributes:
        total (StrictInt): Total number of steps records for the user.
        num_records (StrictInt | None): Number of records in this response.
        page_number (StrictInt | None): Current page number.
        records (list[HealthStepsRead]): List of health steps records.
    """

    total: StrictInt = Field(
        ..., description="Total number of steps records for the user"
    )
    num_records: StrictInt | None = Field(
        default=None, description="Number of records in this response"
    )
    page_number: StrictInt | None = Field(
        default=None, description="Current page number"
    )
    records: list[HealthStepsRead] = Field(
        ..., description="List of health steps records"
    )

    model_config = ConfigDict(
        from_attributes=True,
        extra="forbid",
        validate_assignment=True,
    )

HealthStepsModel

Bases: Base

SQLAlchemy model representing daily step count data for users.

This model stores health and fitness tracking data related to the number of steps taken by a user on a specific date. It includes information about the data source and maintains a relationship with the Users model.

Attributes:

Name Type Description
id Mapped[int]

Primary key, auto-incremented unique identifier.

user_id Mapped[int]

Foreign key referencing users.id.

date Mapped[date]

Calendar date for which the step count is recorded.

steps Mapped[int]

Total number of steps taken on the date.

source Mapped[str | None]

Source of the step data (e.g., fitness device, app).

user Mapped[str | None]

Relationship to the Users model.

Table

health_steps

Relationships
  • Many-to-One with Users model through user_id
Source code in backend/app/health/health_steps/models.py
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class HealthSteps(Base):
    """
    SQLAlchemy model representing daily step count data for users.

    This model stores health and fitness tracking data related to the number of steps
    taken by a user on a specific date. It includes information about the data source
    and maintains a relationship with the Users model.

    Attributes:
        id: Primary key, auto-incremented unique identifier.
        user_id: Foreign key referencing users.id.
        date: Calendar date for which the step count is recorded.
        steps: Total number of steps taken on the date.
        source: Source of the step data (e.g., fitness device, app).
        user: Relationship to the Users model.

    Table:
        health_steps

    Relationships:
        - Many-to-One with Users model through user_id
    """

    __tablename__ = "health_steps"

    id: Mapped[int] = mapped_column(
        primary_key=True,
        autoincrement=True,
    )
    user_id: Mapped[int] = mapped_column(
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
        comment="User ID that the health_steps belongs",
    )
    date: Mapped[date_type] = mapped_column(
        nullable=False,
        index=True,
        comment="Health steps date (date)",
    )
    steps: Mapped[int] = mapped_column(
        nullable=False,
        comment="Number of steps taken",
    )
    source: Mapped[str | None] = mapped_column(
        String(250),
        nullable=True,
        comment="Source of the health steps data",
    )

    # Define a relationship to the Users model
    # TODO: Change to Mapped["User"] when all modules use mapped
    users = relationship("Users", back_populates="health_steps")

HealthStepsRead

Bases: HealthStepsBase

Schema for reading health steps records.

Extends the base health steps schema with an identifier field for retrieving or referencing existing steps records in the database.

Attributes:

Name Type Description
id StrictInt

Unique identifier for the steps record to update. Required field.

user_id StrictInt

Foreign key reference to the user. Required field.

Source code in backend/app/health/health_steps/schema.py
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
class HealthStepsRead(HealthStepsBase):
    """
    Schema for reading health steps records.

    Extends the base health steps schema with an identifier field for retrieving
    or referencing existing steps records in the database.

    Attributes:
        id (StrictInt): Unique identifier for the steps record to update. Required field.
        user_id (StrictInt): Foreign key reference to the user. Required field.
    """

    id: StrictInt = Field(
        ..., description="Unique identifier for the steps record to update"
    )
    user_id: StrictInt = Field(..., description="Foreign key reference to the user")

HealthStepsUpdate

Bases: HealthStepsRead

Schema for updating health steps records.

Inherits from HealthStepsRead to maintain consistency with read operations while allowing modifications to health steps data. This schema is used for PUT/PATCH requests to update existing health steps entries.

Source code in backend/app/health/health_steps/schema.py
91
92
93
94
95
96
97
98
class HealthStepsUpdate(HealthStepsRead):
    """
    Schema for updating health steps records.

    Inherits from HealthStepsRead to maintain consistency with read operations
    while allowing modifications to health steps data. This schema is used for
    PUT/PATCH requests to update existing health steps entries.
    """

Source

Bases: Enum

An enumeration representing supported sources for the application.

Members

GARMIN: Garmin health data source

Source code in backend/app/health/health_steps/schema.py
 6
 7
 8
 9
10
11
12
13
14
class Source(Enum):
    """
    An enumeration representing supported sources for the application.

    Members:
        GARMIN: Garmin health data source
    """

    GARMIN = "garmin"

create_health_steps

create_health_steps(user_id, health_steps, db)

Create a new health steps record for a user.

Parameters:

Name Type Description Default
user_id int

User ID for the record owner.

required
health_steps HealthStepsCreate

Health steps data to create.

required
db Session

Database session.

required

Returns:

Type Description
HealthSteps

Created health steps record.

Raises:

Type Description
HTTPException

If duplicate entry or database error.

Source code in backend/app/health/health_steps/crud.py
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
@core_decorators.handle_db_errors
def create_health_steps(
    user_id: int,
    health_steps: health_steps_schema.HealthStepsCreate,
    db: Session,
) -> health_steps_models.HealthSteps:
    """
    Create a new health steps record for a user.

    Args:
        user_id: User ID for the record owner.
        health_steps: Health steps data to create.
        db: Database session.

    Returns:
        Created health steps record.

    Raises:
        HTTPException: If duplicate entry or database error.
    """
    try:
        # Create a new health_steps
        db_health_steps = health_steps_models.HealthSteps(
            **health_steps.model_dump(exclude_none=False),
            user_id=user_id,
        )

        # Add the health_steps to the database
        db.add(db_health_steps)
        db.commit()
        db.refresh(db_health_steps)

        # Return the health_steps
        return db_health_steps
    except IntegrityError as integrity_error:
        # Rollback the transaction
        db.rollback()

        # Raise an HTTPException with a 409 Conflict status code
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=(
                f"Duplicate entry error. Check if there is already "
                f"a entry created for {health_steps.date}"
            ),
        ) from integrity_error

delete_health_steps

delete_health_steps(user_id, health_steps_id, db)

Delete a health steps record for a user.

Parameters:

Name Type Description Default
user_id int

User ID who owns the record.

required
health_steps_id int

Health steps record ID to delete.

required
db Session

Database session.

required

Returns:

Type Description
None

None

Raises:

Type Description
HTTPException

If record not found or database error.

Source code in backend/app/health/health_steps/crud.py
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
@core_decorators.handle_db_errors
def delete_health_steps(user_id: int, health_steps_id: int, db: Session) -> None:
    """
    Delete a health steps record for a user.

    Args:
        user_id: User ID who owns the record.
        health_steps_id: Health steps record ID to delete.
        db: Database session.

    Returns:
        None

    Raises:
        HTTPException: If record not found or database error.
    """
    # Get the record first to ensure it exists
    db_health_steps = get_health_steps_by_id_and_user_id(health_steps_id, user_id, db)

    # Check if the health_steps was found
    if db_health_steps is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Health steps not found",
        ) from None

    # Delete the health_steps
    db.delete(db_health_steps)
    # Commit the transaction
    db.commit()

edit_health_steps

edit_health_steps(user_id, health_steps, db)

Edit health steps record for a user.

Parameters:

Name Type Description Default
user_id int

User ID who owns the record.

required
health_steps HealthStepsUpdate

Health steps data to update.

required
db Session

Database session.

required

Returns:

Type Description
HealthSteps

Updated HealthSteps model.

Raises:

Type Description
HTTPException

403 if trying to edit other user record, 404 if not found, 500 if database error.

Source code in backend/app/health/health_steps/crud.py
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
@core_decorators.handle_db_errors
def edit_health_steps(
    user_id: int,
    health_steps: health_steps_schema.HealthStepsUpdate,
    db: Session,
) -> health_steps_models.HealthSteps:
    """
    Edit health steps record for a user.

    Args:
        user_id: User ID who owns the record.
        health_steps: Health steps data to update.
        db: Database session.

    Returns:
        Updated HealthSteps model.

    Raises:
        HTTPException: 403 if trying to edit other user record, 404 if not
            found, 500 if database error.
    """
    # Ensure the health_steps belongs to the user
    if health_steps.user_id != user_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Cannot edit health steps for another user.",
        )

    # Get the health_steps from the database
    db_health_steps = get_health_steps_by_id_and_user_id(health_steps.id, user_id, db)

    if db_health_steps is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Health steps not found",
        ) from None

    # Dictionary of the fields to update if they are not None
    health_steps_data = health_steps.model_dump(exclude_unset=True)
    # Iterate over the fields and update the db_health_steps dynamically
    for key, value in health_steps_data.items():
        setattr(db_health_steps, key, value)

    # Commit the transaction
    db.commit()
    # Refresh the object to ensure it reflects database state
    db.refresh(db_health_steps)

    return db_health_steps

get_all_health_steps_by_user_id

get_all_health_steps_by_user_id(user_id, db)

Retrieve all health steps records for a user.

Parameters:

Name Type Description Default
user_id int

User ID to fetch records for.

required
db Session

Database session.

required

Returns:

Type Description
list[HealthSteps]

List of HealthSteps models ordered by date descending.

Raises:

Type Description
HTTPException

If database error occurs.

Source code in backend/app/health/health_steps/crud.py
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@core_decorators.handle_db_errors
def get_all_health_steps_by_user_id(
    user_id: int, db: Session
) -> list[health_steps_models.HealthSteps]:
    """
    Retrieve all health steps records for a user.

    Args:
        user_id: User ID to fetch records for.
        db: Database session.

    Returns:
        List of HealthSteps models ordered by date descending.

    Raises:
        HTTPException: If database error occurs.
    """
    # Get the health_steps from the database
    stmt = (
        select(health_steps_models.HealthSteps)
        .where(health_steps_models.HealthSteps.user_id == user_id)
        .order_by(desc(health_steps_models.HealthSteps.date))
    )
    return db.execute(stmt).scalars().all()

get_health_steps_by_date

get_health_steps_by_date(user_id, date, db)

Retrieve health steps record for a user on a specific date.

Parameters:

Name Type Description Default
user_id int

User ID.

required
date str

Date string for the steps record.

required
db Session

Database session.

required

Returns:

Type Description
HealthSteps | None

HealthSteps model if found, None otherwise.

Raises:

Type Description
HTTPException

If database error occurs.

Source code in backend/app/health/health_steps/crud.py
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
@core_decorators.handle_db_errors
def get_health_steps_by_date(
    user_id: int, date: str, db: Session
) -> health_steps_models.HealthSteps | None:
    """
    Retrieve health steps record for a user on a specific date.

    Args:
        user_id: User ID.
        date: Date string for the steps record.
        db: Database session.

    Returns:
        HealthSteps model if found, None otherwise.

    Raises:
        HTTPException: If database error occurs.
    """
    # Get the health_steps from the database
    stmt = select(health_steps_models.HealthSteps).where(
        health_steps_models.HealthSteps.date == func.date(date),
        health_steps_models.HealthSteps.user_id == user_id,
    )
    return db.execute(stmt).scalar_one_or_none()

get_health_steps_by_id_and_user_id

get_health_steps_by_id_and_user_id(health_steps_id, user_id, db)

Retrieve health steps record by ID and user ID. Args: health_steps_id: Health steps record ID to fetch. user_id: User ID to fetch record for. db: Database session.

Returns:

Type Description
HealthSteps | None

HealthSteps model if found, None otherwise.

Raises: HTTPException: If database error occurs.

Source code in backend/app/health/health_steps/crud.py
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
@core_decorators.handle_db_errors
def get_health_steps_by_id_and_user_id(
    health_steps_id: int, user_id: int, db: Session
) -> health_steps_models.HealthSteps | None:
    """
    Retrieve health steps record by ID and user ID.
    Args:
        health_steps_id: Health steps record ID to fetch.
        user_id: User ID to fetch record for.
        db: Database session.

    Returns:
        HealthSteps model if found, None otherwise.
    Raises:
        HTTPException: If database error occurs.
    """
    # Get the health_steps from the database
    stmt = select(health_steps_models.HealthSteps).where(
        health_steps_models.HealthSteps.id == health_steps_id,
        health_steps_models.HealthSteps.user_id == user_id,
    )
    return db.execute(stmt).scalar_one_or_none()

get_health_steps_number

get_health_steps_number(user_id, db)

Retrieve total count of health steps records for a user.

Parameters:

Name Type Description Default
user_id int

User ID to count records for.

required
db Session

Database session.

required

Returns:

Type Description
int

Total number of health steps records.

Raises:

Type Description
HTTPException

If database error occurs.

Source code in backend/app/health/health_steps/crud.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@core_decorators.handle_db_errors
def get_health_steps_number(user_id: int, db: Session) -> int:
    """
    Retrieve total count of health steps records for a user.

    Args:
        user_id: User ID to count records for.
        db: Database session.

    Returns:
        Total number of health steps records.

    Raises:
        HTTPException: If database error occurs.
    """
    # Get the number of health_steps from the database
    stmt = (
        select(func.count())
        .select_from(health_steps_models.HealthSteps)
        .where(health_steps_models.HealthSteps.user_id == user_id)
    )
    return db.execute(stmt).scalar_one()

get_health_steps_with_pagination

get_health_steps_with_pagination(user_id, db, page_number=1, num_records=5)

Retrieve paginated health steps records for a user.

Parameters:

Name Type Description Default
user_id int

User ID to fetch records for.

required
db Session

Database session.

required
page_number int

Page number to retrieve (1-indexed).

1
num_records int

Number of records per page.

5

Returns:

Type Description
list[HealthSteps]

List of HealthSteps models for the requested page.

Raises:

Type Description
HTTPException

If database error occurs.

Source code in backend/app/health/health_steps/crud.py
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
@core_decorators.handle_db_errors
def get_health_steps_with_pagination(
    user_id: int,
    db: Session,
    page_number: int = 1,
    num_records: int = 5,
) -> list[health_steps_models.HealthSteps]:
    """
    Retrieve paginated health steps records for a user.

    Args:
        user_id: User ID to fetch records for.
        db: Database session.
        page_number: Page number to retrieve (1-indexed).
        num_records: Number of records per page.

    Returns:
        List of HealthSteps models for the requested page.

    Raises:
        HTTPException: If database error occurs.
    """
    # Get the health_steps from the database
    stmt = (
        select(health_steps_models.HealthSteps)
        .where(health_steps_models.HealthSteps.user_id == user_id)
        .order_by(desc(health_steps_models.HealthSteps.date))
        .offset((page_number - 1) * num_records)
        .limit(num_records)
    )
    return db.execute(stmt).scalars().all()