Open In App

Podcast Platform with MERN Stack

Last Updated : 06 May, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we’ll be utilizing the MERN Stack (MongoDB, Express.js, React, Node.js) to develop a comprehensive podcast platform. This project aims to provide a thorough understanding of full-stack development by focusing on backend infrastructure with Express.js and MongoDB for data storage. We’ll cover the creation and management of user profiles, podcast episodes, and interaction data. Additionally, we’ll explore front-end functionality using React to ensure a seamless user experience.

Output Preview: Let us have a look at how the final output will look like.

resize

output

Prerequisites:

Approach to Create Podcast Platform:

  • Define a functional component named App in ‘App.js’.
  • Make a list of necessary dependencies and component and import them.
  • Define Home and saved components and wrap them inside in the App components to provide access to shared context data
  • Use React Router to navigate between different pages.
  • Use Axios to fetch data from backend server.
  • Establish connections to the MongoDB database from the backend server using Mongoose or MongoDB native drivers.

Steps to Create Server

Step 1: Create a new directory named backend.

mkdir backend
cd backend

Step 2: Create a server using the following command in your terminal.

npm init -y

Step 3: Install the necessary package in your server using the following command.

npm install express mongoose body-parser cors

Project Structure:

Screenshot-2024-04-23-115453

project structure

The updated dependencies in package.json file of backend will look like:

 "dependencies": {
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"express": "^4.19.2",
"mongoose": "^8.3.2"
}

Example: Below is an example of creating a server of Podcast Platform application.

JavaScript
// index.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors');

const app = express();
const PORT = process.env.PORT || 5000;

// Middleware
app.use(bodyParser.json());
app.use(cors());

// MongoDB Connection
mongoose.connect('mongodb+srv://shreya:asdf@cluster1.jjrojry.mongodb.net/podcast-app', {
    useNewUrlParser: true,
    useUnifiedTopology: true
})
    .then(() => console.log('MongoDB connected'))
    .catch(err => console.log(err));

// Podcast Model
const podcastSchema = new mongoose.Schema({
    title: {
        type: String,
        required: true
    },
    description: {
        type: String,
        required: true
    },
    audioFile: {
        type: String,
        required: true
    },
    saved: {
        type: Boolean,
        // Default value is false, indicating the podcast is not saved
        default: false
    }
    // Add more fields as needed
});

const Podcast = mongoose.model('Podcast', podcastSchema);

// Routes
// GET all podcasts
app.get('/podcasts', async (req, res) => {
    try {
        const podcasts = await Podcast.find();
        res.json(podcasts);
    } catch (err) {
        res.status(500).json({ message: err.message });
    }
});

// POST a new podcast
app.post('/podcasts', async (req, res) => {
    const podcast = new Podcast({
        title: req.body.title,
        description: req.body.description,
        audioFile: req.body.audioFile
        // 'saved' field defaults to false
    });

    try {
        const newPodcast = await podcast.save();
        res.status(201).json(newPodcast);
    } catch (err) {
        res.status(400).json({ message: err.message });
    }
});
// PUT to update saved field of a podcast
app.put('/podcasts/:id', async (req, res) => {
    try {
        const podcast = await Podcast.findById(req.params.id);
        if (podcast === null) {
            return res.status(404).json({
                message: 'Podcast not found'
            });
        }

        podcast.saved = req.body.saved;
        await podcast.save();

        res.json(podcast);
    } catch (err) {
        res.status(500).json({
            message: err.message
        });
    }
});


// Start server
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

Start your server using the following command:

node index.js

Steps to Create the Frontend and Installing Modules

Step 1: Create the frontend repository named client in the main repository.

mkdir client
cd client

Step 2: Create React project using following command.

npx create-react-app .

Step 3: Install necessary dependencies in your application using following command.

npm install axios react-router-dom

Project Structure:

Screenshot-2024-04-25-103545

project structure

The updated dependencies in package.json file of frontend will look like:

  "dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.6.7",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Example: Below is an example to show the frontend of Podcast Platform application.

CSS
/* style.css */
body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
}

nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20px;
    background-color: #333;
    color: #fff;
}

.logo img {
    width: 70px;
    height: 60px;
    margin-bottom: 10px;
}

.logo span {
    font-size: 1.2rem;
    color: #fff;
    text-decoration: none;
    margin-left: -70px;
    margin-top: 80px;
}

.saved-link a {
    color: #fff;
    text-decoration: none;
    font-size: 1.2rem;
}

.home {
    display: flex;
    flex-wrap: wrap;
    padding: 20px;
}

.podcast {
    width: 28%;
    /* Adjust width to fit three columns in one row */
    background-color: #f4f4f4;
    padding: 20px;
    margin: 10px;
}

button {
    background-color: #007bff;
    color: #fff;
    border: none;
    padding: 8px 16px;
    cursor: pointer;
}

button:hover {
    background-color: #0056b3;
}

.saved {
    padding: 20px;
}

.column {
    width: 45%;
    /* Each column takes up 1/3 of the row */
    float: left;
    padding: 10px;
    box-sizing: border-box;
    /* Include padding and border in width */
}


.saved {
    padding: 20px;
}

#remove_btn {
    background-color: red;
}
JavaScript
//Home.js
import React, {
    useState,
    useEffect
} from 'react';
import axios from 'axios';

const Home = () => {
    const [podcasts, setPodcasts] = useState([]);

    useEffect(() => {
        axios.get('http://localhost:5000/podcasts')
            .then(response => setPodcasts(response.data))
            .catch(error => console.error(
                'Error fetching podcasts:', error));
    }, []);

    const handleSave = (id) => {
        // Call PUT function to save the podcast
        axios.put(`http://localhost:5000/podcasts/${id}`,
            { saved: true })
            .then(response => {
                console.log(`Successfully saved podcast with ID: ${id}`);
                // Update the saved state locally
                setPodcasts(prevPodcasts => {
                    return prevPodcasts.map(podcast => {
                        if (podcast._id === id) {
                            return { ...podcast, saved: true };
                        }
                        return podcast;
                    });
                });
            })
            .catch(error => console.error(
                `Error saving podcast with ID ${id}:`, error));
    };

    return (
        <div className="home">
            {podcasts.map(podcast => (
                <div key={podcast._id} className="podcast">
                    <h2>{podcast.title}</h2>
                    <p>{podcast.description}</p>
                    <audio controls>
                        <source src={podcast.audioFile} type="audio/mp3" />
                        Your browser does not support the audio element.
                    </audio>
                    <button
                        onClick={() => handleSave(podcast._id)}
                        disabled={podcast.saved}>
                        {podcast.saved ? 'Saved' : 'Save'}
                    </button>
                </div>
            ))}
        </div>
    );
};

export default Home;
JavaScript
//App.js
import {
    BrowserRouter as Router,
    Routes,
    Route
} from "react-router-dom";
import Home from "./components/Home.js";
import Saved from "./components/Saved.js";
import Navbar from "./components/Navbar.js";
import "./style.css";

const App = () => {
    return (
        <Router>
            <Navbar />
            <Routes>
                <Route path="/" element={<Home />} />
                <Route path="/saved" element={<Saved />} />
            </Routes>
        </Router>
    );
};

export default App;
JavaScript
//Saved.js
import React, {
    useState,
    useEffect
} from 'react';
import axios from 'axios';

const Saved = () => {
    const [savedPodcasts, setSavedPodcasts] = useState([]);

    useEffect(() => {
        axios.get('http://localhost:5000/podcasts')
            .then(response => {
                // Filter the podcasts that are saved
                const savedPodcasts = response.data.filter(
                    podcast => podcast.saved);
                setSavedPodcasts(savedPodcasts);
            })
            .catch(error => console.error(
                'Error fetching saved podcasts:', error));
    }, []);

    const handleRemove = (id) => {
        axios.put(`http://localhost:5000/podcasts/${id}`,
            { saved: false })
            .then(response => {
                console.log(`Successfully removed podcast with ID: ${id}`);
                // Update the saved state locally
                setSavedPodcasts(prevSavedPodcasts => {
                    return prevSavedPodcasts.filter(
                        podcast => podcast._id !== id);
                });
            })
            .catch(error => console.error(
                `Error removing podcast with ID ${id}:`, error));
    };

    return (
        <div className="saved">
            <h1>Saved Podcasts</h1>
            <div className='home'>
                {savedPodcasts.map(podcast => (
                    <div key={podcast._id} className="podcast">
                        <h2>{podcast.title}</h2>
                        <p>{podcast.description}</p>
                        <audio controls>
                            <source src={podcast.audioFile} type="audio/mp3" />
                            Your browser does not support the audio element.
                        </audio>
                        <button id="remove_btn"
                            onClick={() => handleRemove(podcast._id)}>
                            Remove
                        </button>
                    </div>

                ))}</div>
        </div>
    );
};

export default Saved;
JavaScript
//App.js
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './components/Home';
import Saved from './components/Saved';
import Navbar from './components/Navbar';
import './style.css';

const App = () => {
  return (
    <Router> 
      <Navbar />
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/saved" element={<Saved />} />
      </Routes>
    </Router>
  );
};

export default App;

Start the project using the given command:

npm start
Recording-2024-04-25-101231

output




Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads