Contact API

The Contact API provides endpoints for managing user contacts, including CRUD operations, filtering, and birthday notifications.

Swagger/Redoc UI documentation (Demo)

API Endpoints

List Contacts

Upcoming Birthdays

Get Contact

Create Contact

Update Contact

Delete Contact

Error Responses

Implementation Details

API Layer

Service Layer

Contact management service layer.

This module provides business logic for contact operations including: - Contact creation and validation - Contact retrieval with filtering and pagination - Contact updates and deletion - Birthday reminder functionality - Email uniqueness enforcement

class src.services.contacts.ContactService(db: sqlalchemy.ext.asyncio.AsyncSession)

Bases: object

Service for managing contact operations.

This service handles all contact-related business logic, including: - Contact CRUD operations - Email uniqueness validation - Birthday reminders - Pagination and filtering

Attributes:

repository (ContactRepository): Data access layer for contacts

async create_contact(body: ContactModel, user: User)

Create a new contact for a user.

This method ensures email uniqueness within a user’s contacts before creating the new contact.

Args:

body (ContactModel): Contact data for creation user (User): User who owns the contact

Returns:

Contact: Created contact object

Raises:

EmailValueError: If a contact with the same email already exists

async get_contact(contact_id: int, user: User)

Retrieve a specific contact by ID.

Args:

contact_id (int): ID of the contact to retrieve user (User): User who owns the contact

Returns:

Contact | None: Contact if found, None otherwise

async get_contacts(query: str, skip: int, limit: int, user: User)

Retrieve filtered and paginated contacts for a user.

Args:

query (str): Filter string for searching contacts skip (int): Number of records to skip (offset) limit (int): Maximum number of records to return user (User): User whose contacts to retrieve

Returns:

List[Contact]: List of contacts matching the criteria

async get_upcoming_birthday_contacts(skip, limit, time_range, user: User)

Retrieve contacts with upcoming birthdays.

Args:

skip (int): Number of records to skip (offset) limit (int): Maximum number of records to return time_range (int): Number of days to look ahead user (User): User whose contacts to check

Returns:

List[Contact]: List of contacts with birthdays in the specified range

async remove_contact(contact_id: int, user: User)

Delete a contact.

Args:

contact_id (int): ID of the contact to delete user (User): User who owns the contact

Returns:

Contact: Deleted contact object

async update_contact(contact_id: int, body: ContactModel, user: User)

Update an existing contact.

This method ensures email uniqueness is maintained when updating contact information.

Args:

contact_id (int): ID of the contact to update body (ContactModel): Updated contact data user (User): User who owns the contact

Returns:

Contact: Updated contact object

Raises:

EmailValueError: If the new email conflicts with another contact

Repository Layer

Contact repository module for managing user contacts.

This module provides a repository pattern implementation for contact-related database operations, including: - Contact CRUD operations - Contact filtering and pagination - Birthday reminder functionality - User-specific contact management

class src.repository.contacts.ContactRepository(session: sqlalchemy.ext.asyncio.AsyncSession)

Bases: object

Repository for handling contact-related database operations.

This class provides methods for managing user contacts including: - Creating, reading, updating, and deleting contacts - Filtering and paginating contact lists - Finding contacts by various criteria (ID, email) - Managing upcoming birthday notifications

async create_contact(body: ContactModel, user: User) Contact

Create a new contact for a user.

Args:

body (ContactModel): Contact data including name, email, etc. user_id (int): ID of the user who will own the contact

Returns:

Contact: Created contact object

async get_contact_by_email(contact_email: str, user: User) Contact | None

Retrieve a contact by email address for a user.

Args:

contact_email (str): Email address of the contact user (User): User who owns the contact

Returns:

Contact | None: Contact object if found, None otherwise

async get_contact_by_email_and_contact_id(contact_email: str, contact_id: int, user: User) Contact | None

Find a contact by email excluding a specific contact ID.

Used for checking email uniqueness when updating contacts.

Args:

contact_email (str): Email address to search for contact_id (int): Contact ID to exclude from search user (User): User who owns the contacts

Returns:

Contact | None: Contact object if found, None otherwise

async get_contact_by_id(contact_id: int, user: User) Contact | None

Retrieve a specific contact by ID for a user.

Args:

contact_id (int): ID of the contact to retrieve user (User): User who owns the contact

Returns:

Contact | None: Contact object if found, None otherwise

async get_contacts(query: str, skip: int, limit: int, user: User) List[Contact]

Retrieve filtered and paginated list of user contacts.

Args:

query (str): Filter query string for contact filtering skip (int): Number of records to skip (offset) limit (int): Maximum number of records to return user (User): User whose contacts to retrieve

Returns:

List[Contact]: List of filtered contact objects

async get_upcoming_birthday_contacts(skip: int, limit: int, user: User, time_range: int = 7) List[Contact]

Search contacts in database where birthday for user is in set range.Default - 7 day Debug to change current time manually: current_time = datetime.strptime(“Dec 24 2005 1:33PM”, “%b %d %Y %I:%M%p”)

async remove_contact(contact_id: int, user: User) Contact | None

Delete a contact from the database.

Args:

contact_id (int): ID of the contact to delete user (User): User who owns the contact

Returns:

Contact | None: Deleted contact object if found, None otherwise

async update_contact(contact_id: int, body: ContactModel, user: User) Contact | None

Update an existing contact’s information.

Only updates fields that have changed from their current values.

Args:

contact_id (int): ID of the contact to update body (ContactModel): Updated contact data user (User): User who owns the contact

Returns:

Contact | None: Updated contact object if found, None otherwise

Models and Schemas

Contact Model

class src.schemas.contacts.ContactModel(*args: Any, **kwargs: Any)

Base model for contact data validation.

This model defines the core fields for a contact and their validation rules. Used for both creating new contacts and updating existing ones.

Attributes:

first_name (str): Contact’s first name, max 50 chars last_name (str): Contact’s last name, max 50 chars email (EmailStr): Valid email address, max 255 chars phone (PhoneNumber): Optional phone number in international format birthday (PastDate): Optional birth date, must be in the past description (str): Optional notes about the contact, max 255 chars

Example:
>>> contact = ContactModel(
...     first_name="John",
...     last_name="Doe",
...     email="john@example.com",
...     phone="+1234567890",
...     birthday="1990-01-01"
... )
birthday: pydantic.PastDate | None = None

Contact Response

class src.schemas.contacts.ContactResponse(*args: Any, **kwargs: Any)

Response model for contact data.

Extends the base ContactModel to include database-generated fields that are returned in API responses.

Attributes:

id (int): Contact’s unique identifier created_at (datetime): Timestamp of contact creation updated_at (datetime): Timestamp of last update

Example:
>>> response = ContactResponse(
...     id=1,
...     first_name="John",
...     last_name="Doe",
...     email="john@example.com",
...     created_at="2024-01-01T00:00:00",
...     updated_at="2024-01-01T00:00:00"
... )
created_at: datetime
id: int
updated_at: datetime

Caching

The Contact API implements Redis-based caching for improved performance:

  • Contact lists are cached for 10 seconds

  • Individual contacts are cached for 10 seconds

  • Upcoming birthday lists are cached for 1 hour

Cache is automatically invalidated when contacts are modified.