/api/data/users/search

GET

Search for users by first name, last name, or description. Perfect for recipient autocomplete.

GET /api/data/users/search

Description

The user search endpoint allows you to search for QMail users by their first name, last name, or description field. This endpoint is optimized for autocomplete functionality when composing emails, helping users quickly find recipients by typing partial names.

Autocomplete Use Case

This endpoint is designed for real-time autocomplete features in email composition interfaces. It returns a compact list of matching users with their email addresses, making it easy to implement a responsive "To:" field autocomplete.

Try it Out

http://localhost:8080/api/data/users/search

Query Parameters

Parameter Type Required Description
q string Yes Search query string. Searches against first_name, last_name, and description fields. Case-insensitive partial matching.
limit integer No Maximum number of results to return. Must be between 1 and 100. Default: 20.

Response

Returns a JSON object containing the search query, matching users array, and result count.

Response Properties

query string
The original search query that was executed.
users array<object>
Array of user objects matching the search query. Each object contains UserID, first_name, last_name, email, and description.
count integer
Total number of users found matching the query.
limit integer
The limit parameter used for this search.

Example Response

{
  "query": "john",
  "users": [
    {
      "UserID": 42,
      "first_name": "John",
      "last_name": "Smith",
      "email": "[email protected]",
      "description": "Engineering Team Lead"
    },
    {
      "UserID": 89,
      "first_name": "Johnny",
      "last_name": "Appleseed",
      "email": "[email protected]",
      "description": "Marketing Department"
    },
    {
      "UserID": 156,
      "first_name": "Sarah",
      "last_name": "Johnson",
      "email": "[email protected]",
      "description": "Product Manager"
    }
  ],
  "count": 3,
  "limit": 20
}

User Object Properties

Each user in the results array contains the following properties:

Property Type Description
UserID integer Unique identifier for the user
first_name string User's first name
last_name string User's last name
email string User's QMail email address
description string Optional description/title for the user (e.g., department, role)

Examples

JavaScript (Autocomplete Implementation)

const API_BASE = 'http://localhost:8080/api';

// Debounce function to avoid excessive API calls
function debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
        const later = () => {
            clearTimeout(timeout);
            func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

// Search users for autocomplete
async function searchUsers(query, limit = 20) {
    if (!query || query.length < 2) {
        return [];
    }

    try {
        const params = new URLSearchParams({
            q: query,
            limit: limit.toString()
        });

        const response = await fetch(
            `${API_BASE}/data/users/search?${params}`
        );

        if (!response.ok) {
            throw new Error(`HTTP error ${response.status}`);
        }

        const data = await response.json();
        return data.users;
    } catch (error) {
        console.error('User search failed:', error);
        return [];
    }
}

// Autocomplete implementation
const recipientInput = document.getElementById('to-field');
const autocompleteList = document.getElementById('autocomplete-list');

const handleAutocomplete = debounce(async function(event) {
    const query = event.target.value;

    if (query.length < 2) {
        autocompleteList.style.display = 'none';
        return;
    }

    const users = await searchUsers(query, 10);

    // Clear previous results
    autocompleteList.innerHTML = '';

    if (users.length === 0) {
        autocompleteList.style.display = 'none';
        return;
    }

    // Display results
    users.forEach(user => {
        const item = document.createElement('div');
        item.className = 'autocomplete-item';
        item.innerHTML = `
            ${user.first_name} ${user.last_name}
            ${user.email}
            ${user.description ? `${user.description}` : ''}
        `;

        item.addEventListener('click', () => {
            recipientInput.value = user.email;
            autocompleteList.style.display = 'none';
        });

        autocompleteList.appendChild(item);
    });

    autocompleteList.style.display = 'block';
}, 300);

recipientInput.addEventListener('input', handleAutocomplete);

cURL

# Search for users with name containing "john"
curl "http://localhost:8080/api/data/users/search?q=john"

# Search with custom limit
curl "http://localhost:8080/api/data/users/search?q=smith&limit=5"

# Search by partial first name
curl "http://localhost:8080/api/data/users/search?q=sar"

# Pretty print the JSON response
curl "http://localhost:8080/api/data/users/search?q=johnson" | jq

# Extract just the email addresses
curl -s "http://localhost:8080/api/data/users/search?q=dev" | \
  jq -r '.users[].email'

Python

import requests
from typing import List, Dict, Optional

API_BASE = 'http://localhost:8080/api'

def search_users(query: str, limit: int = 20) -> Dict:
    """
    Search for users by name or description.

    Args:
        query: Search query string (first name, last name, or description)
        limit: Maximum results to return (1-100, default 20)

    Returns:
        Dictionary with query, users array, count, and limit
    """
    params = {
        'q': query,
        'limit': limit
    }

    response = requests.get(
        f'{API_BASE}/data/users/search',
        params=params
    )
    response.raise_for_status()

    data = response.json()

    print(f"Found {data['count']} users matching '{query}'\n")

    for user in data['users']:
        full_name = f"{user['first_name']} {user['last_name']}"
        print(f"{full_name} <{user['email']}>")
        if user.get('description'):
            print(f"  {user['description']}")
        print()

    return data


def get_user_emails(query: str) -> List[str]:
    """
    Get just the email addresses for users matching query.

    Args:
        query: Search query string

    Returns:
        List of email addresses
    """
    data = search_users(query, limit=100)
    return [user['email'] for user in data['users']]


# Example usage
if __name__ == '__main__':
    # Search for users
    results = search_users('john', limit=10)

    # Get just email addresses
    emails = get_user_emails('engineering')
    print(f"Engineering emails: {', '.join(emails)}")

    # Autocomplete simulation
    def autocomplete(partial_name: str) -> List[Dict]:
        """Simulate autocomplete with minimum 2 characters."""
        if len(partial_name) < 2:
            return []
        data = search_users(partial_name, limit=5)
        return data['users']

    suggestions = autocomplete('sar')
    for user in suggestions:
        print(f"{user['first_name']} {user['last_name']} - {user['email']}")

Implementation Tips

Best Practices for Autocomplete
  • Debouncing: Use a debounce function (300ms recommended) to avoid excessive API calls while the user is typing.
  • Minimum Characters: Wait for at least 2-3 characters before triggering a search to reduce noise and server load.
  • Result Limit: For autocomplete, use a small limit (5-10 results) to keep the dropdown manageable.
  • Caching: Consider caching recent search results to improve responsiveness.
  • Keyboard Navigation: Implement arrow key navigation and Enter to select for better UX.

Related Endpoints

Search Emails

Search for emails using full-text search across subjects, bodies, and other fields.

GET /api/data/users

Retrieve the complete list of users with filtering options. Use this for browsing all users.