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