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_by_user_id, get_health_steps_by_id_and_user_id, get_health_steps_by_user_id, get_health_steps_by_date_and_user_id, 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
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
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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
62
63
64
65
66
67
68
69
70
71
72
@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: HealthListResponse

Response model for listing health steps records.

Extends the base HealthListResponse to provide a typed response containing a list of steps records. This model is used when returning multiple steps entries from API endpoints.

Attributes:

Name Type Description
records list[HealthStepsRead]

A list of HealthStepsRead objects representing individual steps records.

Source code in backend/app/health/health_steps/schema.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
class HealthStepsListResponse(health_schema.HealthListResponse):
    """
    Response model for listing health steps records.

    Extends the base HealthListResponse to provide a typed response containing
    a list of steps records. This model is used when returning multiple steps
    entries from API endpoints.

    Attributes:
        records: A list of HealthStepsRead objects representing individual
            steps records.
    """

    records: list[HealthStepsRead] = Field(
        ..., description="List of health steps records"
    )

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
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
60
61
62
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
    users: Mapped["Users"] = relationship(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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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
 93
 94
 95
 96
 97
 98
 99
100
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
 8
 9
10
11
12
13
14
15
16
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
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
191
192
193
194
@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
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
274
275
276
277
@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
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
242
243
244
245
@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_health_steps_by_date_and_user_id

get_health_steps_by_date_and_user_id(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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
@core_decorators.handle_db_errors
def get_health_steps_by_date_and_user_id(
    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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
@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_by_user_id

get_health_steps_by_user_id(user_id, db, page_number=None, num_records=None, interval=None)

Retrieve health steps records for a specific user with optional pagination and filtering.

Parameters:

Name Type Description Default
user_id int

The ID of the user whose health steps records are to be retrieved.

required
db Session

The database session used to execute the query.

required
page_number int | None

The page number for pagination (1-indexed). If provided, num_records must also be provided. Defaults to None.

None
num_records int | None

The number of records per page. If provided, page_number must also be provided. Defaults to None.

None
interval Interval | None

The time interval to filter records. If provided, only records from the start of the interval to present are returned. Defaults to None.

None

Returns:

Type Description
list[HealthSteps]

list[health_steps_models.HealthSteps]: A list of health steps records sorted by date in descending order, optionally paginated.

Source code in backend/app/health/health_steps/crud.py
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 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
117
118
119
120
@core_decorators.handle_db_errors
def get_health_steps_by_user_id(
    user_id: int,
    db: Session,
    page_number: int | None = None,
    num_records: int | None = None,
    interval: health_constants.Interval | None = None,
) -> list[health_steps_models.HealthSteps]:
    """
    Retrieve health steps records for a specific user with optional pagination
        and filtering.

    Args:
        user_id (int): The ID of the user whose health steps records are to be
            retrieved.
        db (Session): The database session used to execute the query.
        page_number (int | None, optional): The page number for pagination
            (1-indexed).
            If provided, num_records must also be provided. Defaults to None.
        num_records (int | None, optional): The number of records per page.
            If provided, page_number must also be provided. Defaults to None.
        interval (health_constants.Interval | None, optional): The time
            interval to filter records.
            If provided, only records from the start of the interval to present
            are returned. Defaults to None.

    Returns:
        list[health_steps_models.HealthSteps]: A list of health steps
            records sorted by date in descending order, optionally paginated.
    """
    # Get the health_steps from the database
    stmt = select(health_steps_models.HealthSteps).where(
        health_steps_models.HealthSteps.user_id == user_id
    )

    if interval is not None:
        stmt = stmt.where(
            health_steps_models.HealthSteps.date
            >= health_utils.get_start_date_for_interval(interval.value)
        )

    stmt = stmt.order_by(desc(health_steps_models.HealthSteps.date))

    if page_number is not None and num_records is not None:
        stmt = stmt.offset((page_number - 1) * num_records).limit(num_records)

    return db.execute(stmt).scalars().all()

get_health_steps_number_by_user_id

get_health_steps_number_by_user_id(user_id, db, interval=None)

Retrieve total count of health steps records for a user. If interval is provided, count only records starting from the calculated start date.

Parameters:

Name Type Description Default
user_id int

User ID to count records for.

required
db Session

Database session.

required
interval Interval | None

Optional filter by goal interval.

None

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
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
@core_decorators.handle_db_errors
def get_health_steps_number_by_user_id(
    user_id: int, db: Session, interval: health_constants.Interval | None = None
) -> int:
    """
    Retrieve total count of health steps records for a user. If interval is
    provided, count only records starting from the calculated start date.

    Args:
        user_id: User ID to count records for.
        db: Database session.
        interval: Optional filter by goal interval.

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

    if interval is not None:
        stmt = stmt.where(
            health_steps_models.HealthSteps.date
            >= health_utils.get_start_date_for_interval(interval.value)
        )

    return db.execute(stmt).scalar_one()