A modern tennis website built with Astro that displays live ATP rankings and match results using the SportRadar Tennis API.
- 🏆 Live ATP Rankings - Top 100 ATP players with points and position changes
- 🎾 Live Matches - Real-time scores from ATP and Challenger tournaments
- 📱 Responsive Design - Works perfectly on desktop, tablet, and mobile
- 🌙 Dark Mode - Automatic dark/light theme switching
- ⚡ Fast Performance - Built with Astro for optimal loading speeds
- Framework: Astro v5
- Styling: Tailwind CSS v4
- API: SportRadar Tennis API
- TypeScript: Full type safety
- Architecture: API-agnostic design pattern
- Node.js 18+ and npm
- SportRadar Tennis API key (trial version included)
-
Clone and install dependencies:
cd tenis-app npm install -
Configure API key:
The SportRadar API key is already configured in the
.envfile:SPORTRADAR_API_KEY=ghFUX4ygnpBf7wX2Ua6ZtTnfFWdEg0JWKQ4envGp -
Test API connection (optional):
node test-api.js
-
Start development server:
npm run dev
-
Open your browser:
http://localhost:4321
npm run build
npm run previewtenis-app/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── Header.astro # Navigation header
│ │ ├── RankingsTable.astro # ATP rankings table
│ │ ├── MatchCard.astro # Match information card
│ │ └── MatchesList.astro # List of matches
│ ├── layouts/ # Page layouts
│ │ └── Layout.astro # Base layout
│ ├── lib/ # Business logic
│ │ └── api/ # API abstraction layer
│ │ ├── types.ts # TypeScript interfaces
│ │ ├── tennisApi.ts # Main API service
│ │ └── providers/
│ │ └── sportradar.ts # SportRadar implementation
│ ├── pages/ # Route pages
│ │ ├── index.astro # Home page
│ │ ├── rankings.astro # ATP rankings page
│ │ └── matches.astro # Live matches page
│ ├── styles/ # Global styles
│ │ └── global.css # Tailwind base styles
│ └── site.config.ts # Site configuration
├── public/ # Static assets
└── package.json
The application uses SportRadar's Tennis API v3 with the following endpoints:
- Rankings:
/rankings.json- ATP player rankings - Live Matches:
/schedules/live/summaries.json- Currently live matches - Daily Schedule:
/schedules/{date}/summaries.json- Today's match schedule
The application uses an API-agnostic pattern that allows easy switching between different tennis data providers:
// Main API service
import { tennisApi } from '@/lib/api/tennisApi';
// Get ATP rankings (top 100)
const rankings = await tennisApi.getATPRankings(100);
// Get live matches
const liveMatches = await tennisApi.getLiveMatches();
// Get today's matches
const todayMatches = await tennisApi.getTodayMatches();To use a different API provider, implement the TennisApiProvider interface:
class NewProvider implements TennisApiProvider {
async getRankings(type: "ATP" | "WTA", limit?: number): Promise<Rankings> {
// Implementation
}
async getLiveMatches(): Promise<LiveMatches> {
// Implementation
}
async getTodayMatches(): Promise<LiveMatches> {
// Implementation
}
}
// Switch provider
tennisApi.setProvider(new NewProvider());npm run dev- Start development servernpm run build- Build for productionnpm run preview- Preview production buildnpm run check- Run Astro checksnpm run format- Format code with Prettiernpm run lint- Lint code with Biome
The application includes comprehensive error handling:
- API Failures: Clear error messages with retry options
- Network Issues: Graceful degradation with user feedback
- Rate Limiting: Proper error display for API limits
- Invalid Responses: Type-safe error handling
- Server-Side Rendering: Fast initial page loads
- Static Generation: Optimized for performance
- Image Optimization: Automatic image optimization
- Code Splitting: Minimal JavaScript bundles
- Fork the repository
- Create a feature branch
- Make changes following the existing patterns
- Test your changes
- Submit a pull request
MIT License - see LICENSE file for details
For issues with:
- SportRadar API: Check the SportRadar Developer Portal
- Application bugs: Create an issue in this repository
- Feature requests: Create an issue with the "enhancement" label