/api/data/users/search
GETSearch for users by first name, last name, or description. Perfect for recipient autocomplete.
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.
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
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
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
- 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.