Sports Scoreboard SaaS Node.js
👤 Sharing: AI
```javascript
// sports-scoreboard-api.js (Main API file)
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors'); // Import the cors middleware
const app = express();
const port = process.env.PORT || 3000;
// In-memory data store (replace with a database for production)
let scoreboard = {
basketball: {
gameId: 'bball-001',
teamA: 'Lakers',
teamB: 'Celtics',
scoreA: 0,
scoreB: 0,
period: '1st Quarter',
timeRemaining: '10:00'
},
football: {
gameId: 'fball-001',
teamA: 'Chiefs',
teamB: 'Eagles',
scoreA: 0,
scoreB: 0,
quarter: '1st Quarter',
timeRemaining: '15:00'
},
soccer: {
gameId: 'soccer-001',
teamA: 'Barcelona',
teamB: 'Real Madrid',
scoreA: 0,
scoreB: 0,
period: '1st Half',
timeRemaining: '45:00'
}
};
// Middleware
app.use(bodyParser.json());
app.use(cors()); // Enable CORS for all routes
// --- Helper Functions ---
function isValidSport(sport) {
return Object.keys(scoreboard).includes(sport);
}
// --- API Endpoints ---
// 1. Get Scoreboard for a Specific Sport
app.get('/api/scoreboard/:sport', (req, res) => {
const sport = req.params.sport;
if (!isValidSport(sport)) {
return res.status(400).json({ error: 'Invalid sport provided.' });
}
res.json(scoreboard[sport]);
});
// 2. Update Score
app.put('/api/scoreboard/:sport/score', (req, res) => {
const sport = req.params.sport;
const { team, points } = req.body; // Expecting { team: 'teamA' or 'teamB', points: number }
if (!isValidSport(sport)) {
return res.status(400).json({ error: 'Invalid sport provided.' });
}
if (!team || !['teamA', 'teamB'].includes(team) || !Number.isInteger(points)) {
return res.status(400).json({ error: 'Invalid request body. Must include team (teamA or teamB) and points (integer).' });
}
try {
scoreboard[sport][`score${team.slice(4).toUpperCase()}`] += points; // Dynamic access
res.json(scoreboard[sport]); // Respond with the updated scoreboard
} catch (error) {
console.error("Error updating score:", error);
res.status(500).json({ error: 'Failed to update score.' });
}
});
// 3. Update Game Clock
app.put('/api/scoreboard/:sport/clock', (req, res) => {
const sport = req.params.sport;
const { timeRemaining } = req.body;
if (!isValidSport(sport)) {
return res.status(400).json({ error: 'Invalid sport provided.' });
}
if (!timeRemaining || typeof timeRemaining !== 'string') {
return res.status(400).json({ error: 'Invalid request body. Must include timeRemaining (string).' });
}
try {
scoreboard[sport].timeRemaining = timeRemaining;
res.json(scoreboard[sport]); // Respond with the updated scoreboard
} catch (error) {
console.error("Error updating clock:", error);
res.status(500).json({ error: 'Failed to update clock.' });
}
});
// 4. Update Period/Quarter/Half
app.put('/api/scoreboard/:sport/period', (req, res) => {
const sport = req.params.sport;
const { period } = req.body;
if (!isValidSport(sport)) {
return res.status(400).json({ error: 'Invalid sport provided.' });
}
if (!period || typeof period !== 'string') {
return res.status(400).json({ error: 'Invalid request body. Must include period (string).' });
}
try {
if (sport === 'football') {
scoreboard[sport].quarter = period;
} else if (sport === 'soccer') {
scoreboard[sport].period = period;
}
else {
scoreboard[sport].period = period; // Default for basketball and others
}
res.json(scoreboard[sport]);
} catch (error) {
console.error("Error updating period:", error);
res.status(500).json({ error: 'Failed to update period.' });
}
});
// Start the server
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
```
**Explanation:**
1. **Dependencies:**
* `express`: A minimalist web framework for Node.js. Makes it easy to create APIs.
* `body-parser`: Middleware that parses incoming request bodies in JSON format. Allows you to access the data sent in the request body (e.g., when updating the score).
* `cors`: Middleware to enable Cross-Origin Resource Sharing (CORS). This is crucial if your frontend (e.g., a React app) is running on a different domain or port than your backend, as it allows the frontend to make requests to the backend API.
2. **Setup:**
* `const app = express();`: Creates an Express application.
* `const port = process.env.PORT || 3000;`: Sets the port the server will listen on. `process.env.PORT` is used for deployment (e.g., on Heroku); if it's not set, it defaults to port 3000.
* `app.use(bodyParser.json());`: Registers the `body-parser` middleware so that JSON request bodies are parsed.
* `app.use(cors());`: Enables CORS for all routes.
3. **In-Memory Data Store:**
* `scoreboard`: A JavaScript object that simulates a database. **Important:** In a real-world application, you would replace this with a persistent database (e.g., MongoDB, PostgreSQL, MySQL). This example uses an in-memory store for simplicity. It contains sample data for basketball, football, and soccer. Each sport has a `gameId`, `teamA`, `teamB`, `scoreA`, `scoreB`, and either `period`/`quarter` and `timeRemaining`.
4. **API Endpoints:**
* **`GET /api/scoreboard/:sport`**: Retrieves the scoreboard data for a specific sport.
* `req.params.sport`: Gets the sport from the URL (e.g., `/api/scoreboard/basketball`).
* `res.json(scoreboard[sport])`: Sends the scoreboard data as a JSON response.
* Error handling: Checks if the sport is valid. If not, returns a 400 Bad Request error.
* **`PUT /api/scoreboard/:sport/score`**: Updates the score for a specific team in a specific sport.
* `req.body`: Expects a JSON payload like `{ team: 'teamA', points: 3 }`.
* `scoreboard[sport][`score${team.slice(4).toUpperCase()}`] += points;`: Dynamically updates the score based on the `team` value. For example, if `team` is `'teamA'`, it updates `scoreboard[sport].scoreA`.
* Error handling: Checks for a valid sport, that the required request body parameters are present, and that points is an integer.
* **`PUT /api/scoreboard/:sport/clock`**: Updates the game clock (time remaining) for a specific sport.
* `req.body`: Expects a JSON payload like `{ timeRemaining: '05:30' }`.
* `scoreboard[sport].timeRemaining = timeRemaining;`: Updates the `timeRemaining` property.
* Error handling: Checks for valid sport and that the `timeRemaining` is a string.
* **`PUT /api/scoreboard/:sport/period`**: Updates the period/quarter/half for a specific sport.
* `req.body`: Expects a JSON payload like `{ period: '2nd Half' }`.
* Updates the `period` or `quarter` property depending on the sport.
* Error handling: Checks for valid sport and that `period` is a string.
5. **Starting the Server:**
* `app.listen(port, () => { ... });`: Starts the Express server and listens for incoming requests on the specified port. The callback function logs a message to the console.
**How to Run:**
1. **Install Node.js and npm:** Make sure you have Node.js and npm (Node Package Manager) installed on your system.
2. **Create a Project Directory:** Create a new directory for your project (e.g., `sports-scoreboard`).
3. **Initialize npm:** Inside the project directory, run `npm init -y` to create a `package.json` file.
4. **Install Dependencies:** Run `npm install express body-parser cors` to install the required dependencies.
5. **Create the `sports-scoreboard-api.js` File:** Copy the code above into a file named `sports-scoreboard-api.js`.
6. **Start the Server:** Run `node sports-scoreboard-api.js` in your terminal. You should see the message "Server listening on port 3000".
**How to Test (using curl):**
Open a separate terminal window to test the API.
* **Get Scoreboard:**
```bash
curl http://localhost:3000/api/scoreboard/basketball
```
* **Update Basketball Score:**
```bash
curl -X PUT -H "Content-Type: application/json" -d '{"team": "teamA", "points": 2}' http://localhost:3000/api/scoreboard/basketball
```
* **Update Football Clock:**
```bash
curl -X PUT -H "Content-Type: application/json" -d '{"timeRemaining": "12:00"}' http://localhost:3000/api/scoreboard/football
```
* **Update Soccer Period:**
```bash
curl -X PUT -H "Content-Type: application/json" -d '{"period": "2nd Half"}' http://localhost:3000/api/scoreboard/soccer
```
**Next Steps and Improvements:**
* **Database Integration:** Replace the in-memory `scoreboard` object with a real database (e.g., MongoDB, PostgreSQL). Use a database library like `mongoose` (for MongoDB) or `pg` (for PostgreSQL).
* **Data Validation:** Add more robust data validation using libraries like `express-validator` to ensure that the data being sent to the API is valid.
* **Authentication/Authorization:** Implement authentication (e.g., using JSON Web Tokens - JWT) to protect your API endpoints and ensure that only authorized users can update the scoreboard.
* **Frontend:** Create a frontend (e.g., using React, Angular, Vue.js) to display the scoreboard data and allow users to interact with the API.
* **Error Handling:** Implement more comprehensive error handling and logging to make the application more robust.
* **Real-time Updates (WebSockets):** For a truly real-time scoreboard experience, use WebSockets (e.g., with the `socket.io` library) to push updates to connected clients as soon as the data changes on the server.
* **Testing:** Write unit tests and integration tests to ensure the API is working correctly.
This example provides a basic foundation for a sports scoreboard API using Node.js, Express, and JavaScript. Remember to replace the in-memory data store with a database and add authentication and other security measures for a production environment.
👁️ Viewed: 5
Comments