Endpoint
GET /api/participants?name={name}&company={company}
Description
Searches for participants by partial name match within a specific school. This endpoint allows users to find children who have participated in the Tamborrada Infantil across different years.
Important: For privacy and accuracy, the search requires a minimum of first name + two surnames and an exact school name.
Authentication
No authentication required. This is a public endpoint.
Query Parameters
The participant’s full name to search for. Must include at least:
- First name
- Two surnames (Spanish/Basque naming convention)
The name is normalized (diacritics removed) and supports partial matching.Example: “Juan Garcia Lopez”
The exact school/company name. Must match exactly one of the values from /api/companies.Example: “Amara Berri”
Response
Array of participant records, sorted by year (descending). Each record contains:
name (string): Full name of the participant (normalized)
school (string): School/company name
year (number): Year of participation
Success Response (200 OK)
{
"participants": [
{
"name": "Juan Garcia Lopez",
"school": "Amara Berri",
"year": 2024
},
{
"name": "Juan Garcia Lopez",
"school": "Amara Berri",
"year": 2023
},
{
"name": "Juan Garcia Lopez",
"school": "Amara Berri",
"year": 2022
}
]
}
Error Responses
Missing Parameters (400 Bad Request)
{
"error": "Parametros 'name' y 'company' son obligatorios"
}
Insufficient Name Parts (400 Bad Request)
{
"error": "Por favor, proporciona al menos un nombre y dos apellidos"
}
Returned when the name has fewer than 3 parts (first name + 2 surnames).
No Participants Found (500 Internal Server Error)
{
"error": "Error: No participants found"
}
Returned when no matching participants are found for the given name and school.
Server Error (500 Internal Server Error)
{
"error": "Error al obtener el estado del sistema",
"details": "<technical details>"
}
Examples
cURL
# Search for a participant
curl "https://tamborradata.com/api/participants?name=Juan%20Garcia%20Lopez&company=Amara%20Berri"
# Note: URL encode spaces as %20
JavaScript (Fetch)
async function searchParticipant(name, company) {
const params = new URLSearchParams({ name, company });
const response = await fetch(
`https://tamborradata.com/api/participants?${params}`
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error);
}
const data = await response.json();
return data.participants;
}
// Usage
try {
const results = await searchParticipant(
'Juan Garcia Lopez',
'Amara Berri'
);
console.log(`Found ${results.length} participation(s)`);
results.forEach(p => {
console.log(`${p.year}: ${p.name} at ${p.school}`);
});
} catch (error) {
console.error('Search failed:', error.message);
}
JavaScript (Axios)
const axios = require('axios');
try {
const { data } = await axios.get(
'https://tamborradata.com/api/participants',
{
params: {
name: 'Maria Rodriguez Sanchez',
company: 'Santo Tomas Lizeoa'
}
}
);
console.log('Participants:', data.participants);
} catch (error) {
if (error.response?.status === 400) {
console.error('Invalid search parameters');
} else if (error.response?.status === 500) {
console.log('No participants found');
} else {
console.error('Error:', error.response?.data?.error);
}
}
Python
import requests
from urllib.parse import urlencode
def search_participant(name, company):
params = {'name': name, 'company': company}
response = requests.get(
'https://tamborradata.com/api/participants',
params=params
)
if response.status_code == 200:
data = response.json()
return data['participants']
else:
error = response.json()
raise Exception(error['error'])
# Usage
try:
results = search_participant(
'Ana Lopez Gonzalez',
'La Salle Ikastetxea'
)
print(f"Found {len(results)} participation(s)")
for p in results:
print(f"{p['year']}: {p['name']} at {p['school']}")
except Exception as e:
print(f"Error: {e}")
TypeScript
type Participant = {
name: string;
school: string;
year: number;
};
type ParticipantsResponse = {
participants: Participant[];
};
type ErrorResponse = {
error: string;
};
async function searchParticipant(
name: string,
company: string
): Promise<Participant[]> {
// Validate name has at least 3 parts
const nameParts = name.trim().split(/\s+/);
if (nameParts.length < 3) {
throw new Error('Name must include first name and two surnames');
}
const params = new URLSearchParams({ name, company });
const response = await fetch(
`https://tamborradata.com/api/participants?${params}`
);
if (!response.ok) {
const error: ErrorResponse = await response.json();
throw new Error(error.error);
}
const data: ParticipantsResponse = await response.json();
return data.participants;
}
// Usage
try {
const participants = await searchParticipant(
'Carlos Perez Ruiz',
'Ekintza Ikastola'
);
if (participants.length > 0) {
console.log('Participation history:');
participants.forEach(p => {
console.log(` ${p.year}: ${p.school}`);
});
} else {
console.log('No participations found');
}
} catch (error) {
console.error('Search error:', error);
}
Implementation Details
Source Code Reference
The endpoint is implemented in:
- Route:
app/(backend)/api/participants/route.ts:6
- Service:
app/(backend)/api/participants/services/participants.service.ts
- Repository:
app/(backend)/api/participants/repositories/participants.repo.ts:6
- Validation:
app/(backend)/api/participants/dtos/participants.schema.ts:5
Data Flow
- Extract
name and company query parameters
- Validate both parameters are provided
- Normalize name (remove diacritics, trim whitespace)
- Validate name has at least 3 parts (first + 2 surnames)
- Query
participants table with ILIKE for partial match
- Filter by exact school match
- Order results by year (descending)
- Return array of participants
Name Normalization
Names are normalized using:
const cleanName = name
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '') // Remove diacritics
.replace(/\s+/g, ' ') // Normalize whitespace
.trim();
This allows matching names with or without accents:
- “José” matches “Jose”
- “María” matches “Maria”
- “Ñ” matches “N”
Database Query
The endpoint executes:
SELECT name, school, year
FROM participants
WHERE name ILIKE $1
AND school = $2
ORDER BY year DESC;
Where $1 is %{cleanName}% (partial match) and $2 is the exact school name.
Use Cases
async function handleSearchForm(event) {
event.preventDefault();
const formData = new FormData(event.target);
const name = formData.get('name');
const company = formData.get('company');
try {
const participants = await searchParticipant(name, company);
displayResults(participants);
} catch (error) {
displayError(error.message);
}
}
function displayResults(participants) {
const container = document.getElementById('results');
container.innerHTML = participants
.map(p => `<li>${p.year}: ${p.name} - ${p.school}</li>`)
.join('');
}
2. Check Participation History
async function getParticipationYears(name, company) {
try {
const participants = await searchParticipant(name, company);
return participants.map(p => p.year);
} catch (error) {
return [];
}
}
const years = await getParticipationYears(
'Juan Garcia Lopez',
'Amara Berri'
);
console.log('Participated in:', years.join(', '));
3. Verify Participation
async function didParticipateInYear(name, company, year) {
try {
const participants = await searchParticipant(name, company);
return participants.some(p => p.year === year);
} catch (error) {
return false;
}
}
const participated = await didParticipateInYear(
'Maria Rodriguez Sanchez',
'La Salle Ikastetxea',
2024
);
console.log('Participated in 2024:', participated);
Notes
Names in the database are stored normalized (without diacritics). The API handles normalization automatically.
The company parameter must match exactly (case-sensitive). Use /api/companies to get valid school names.
Partial name matching is supported. Searching “Juan Garcia” will match “Juan Garcia Lopez”, “Juan Garcia Ruiz”, etc.
Spanish Naming Convention
Spanish and Basque names typically follow the pattern:
[First Name] [Father's Surname] [Mother's Surname]
Examples:
- Juan Garcia Lopez
- Maria Rodriguez Sanchez
- Ane Etxeberria Agirre
The API requires all three parts to ensure accurate identification.
Privacy Considerations
This endpoint returns participant data from published historical records. The data:
- Comes from public Tamborrada participation lists
- Is historical (not real-time)
- Requires full name + school to query (not easily enumerable)
- Is intended for legitimate research and statistical purposes
This API returns data from mock/synthetic records in this demo. Production data follows strict privacy guidelines.
- Response Time: 100-200ms
- Database Query: ILIKE query with index on
name and school
- Caching: Not recommended (data is user-specific)
- Payload Size: Varies (typically < 5 KB)
Error Handling
async function searchParticipantSafely(name, company) {
try {
// Client-side validation
if (!name || !company) {
throw new Error('Name and company are required');
}
const nameParts = name.trim().split(/\s+/);
if (nameParts.length < 3) {
throw new Error(
'Please provide first name and two surnames'
);
}
const params = new URLSearchParams({ name, company });
const response = await fetch(
`https://tamborradata.com/api/participants?${params}`
);
if (!response.ok) {
const error = await response.json();
if (response.status === 500 &&
error.error.includes('No participants found')) {
// Not an error, just no results
return [];
}
throw new Error(error.error);
}
const data = await response.json();
return data.participants || [];
} catch (error) {
console.error('Participant search error:', error);
throw error;
}
}
Name Search Tips
Handling Special Characters
// API handles normalization, but you can pre-normalize:
function normalizeInput(str) {
return str
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.trim();
}
const userInput = 'José María García';
const normalized = normalizeInput(userInput);
// Result: "Jose Maria Garcia"
Partial Name Matching
// These searches will work:
await searchParticipant('Juan Garcia Lopez', 'Amara Berri');
await searchParticipant('Garcia Lopez', 'Amara Berri'); // Partial
await searchParticipant('Juan', 'Amara Berri'); // Too short, but will match
// Remember: Still need 3 parts for validation