Contact API
The Contact API provides endpoints for managing user contacts, including CRUD operations, filtering, and birthday notifications.
Swagger/Redoc UI documentation (Demo)
Interactive API documentation: https://try.api.ucontacts.d0s.site/docs
Alternative API documentation: https://try.api.ucontacts.d0s.site/redoc
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:
objectService 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:
objectRepository 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.