Save your favorite movies and give them your own description!
Responsive full-stack website using React & Node.js. The website supports user authentication with Passport.js allowing users to register, login and create personalized lists of movies.
The project includes an SQL database with one-to-many relationship configured with Sequelize ORM.
A CRUD API allows users to edit movies in their list. An external movie library is connected with RapidAPI to fetch the initial data about movies.
Universal API interface automatically fetches movie data depending on the movie status. That is, a local database if the movie is saved, or the external API otherwise.
The app allows the user to:
- Register & login to an account
- View movie descriptions and search for movies
- Add movies to their list & view their list of movies
- Edit the description of each movie that they saved
- Delete movies from their list (description is reset to default)
Your.Movie.List.Demo.Compressed.Twice.mp4
Make sure to have npm installed
Clone the repository
git clone https://github.com/Vladmidir/Your-Movie-List.git
cd Your-Movie-List
Install the dependencies
npm install
CD into the client folder, install client dependencies, and build the react app
cd client
npm install
npm run build
cd ..
Create a RapidAPI account and get a RapidAPI Movies Database key from here.
Add your RapidAPI key to a .env
file and source it
./server/.env
export RAPIDAPI_KEY='yourkey'
source ./server/.env
From the project root folder start the server
npm start
Check the http://localhost:8080/
or the port displayed in your terminal.
The project uses React client-side rendering along with an Express server.
Whenever a request is sent to the server that does not match any server routes, the server redirects the request to the client
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "../client/build", "index.html"))
})
All of the rendering is done by the client.
The server contains authentication POST routes for registering and authenticating the user.
app.post("/api/register", checkNotAuthenticated, async (req, res) => {
//some code...
}
app.post("/api/login", checkNotAuthenticated, passport.authenticate('local', {
successRedirect: '/',
}))
//etc.
Along with authentication, the server has the movie
API route. The movie
route provides a universal interface for interacting with the local database (supporting CRUD) and the RapidAPI MoviesDatabase API.
const movies = require("./routes/Movie.router.js")
app.use('/api/movie', checkAuthenticated, movies)
Notice that the Movie.router.js does not contain any logic. All of the API & database managment logic is contained in Movie.controlles.js and is imported into the router.
The initial data for the movie is retrieved by the movie API from RapidAPI MoivesDatabase.
When a user adds a movie to their list, a record is created in the database. The information about the movie is now stored locally along with the UserId of the user that saved the movie (one-to-many relationship).
// Create and Save a new Movie
exports.create = (req, res) => {
// Validate request
//NOTE: Other fields can be empty, due to the RapidAPI imperfections
if (!req.body.title) {
res.status(400).send({
message: "Title can not be empty!"
});
return;
}
// Create a Movie. Add the UserId here.
const newMovie = {
title: req.body.title,
description: req.body.description,
imdb_id: req.body.imdb_id,
rating: req.body.rating,
banner: req.body.banner,
genre: req.body.genre,
UserId: req.user.id
};
// Save the Movie in the database
Movie.create(newMovie)
.then(data => {
//redirect back to the Movie's page
res.status(200).redirect("../movie/" + data.imdb_id);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while creating the Movie."
});
});
};
When querying for a movie, the server first checks the local database for if the user has saved the corresponding movie. If the user has not saved the movie, the data from RapidAPI MoviesDatabase is then returned.
// Find a single Movie with an id as a parameter
exports.findOne = async (req, res) => {
movie_id = req.params.id
//have to check if it is in the database, if not request the RapidAPI
movieLocal = await Movie.findOne({
where: {
imdb_id: movie_id,
UserId: req.user.id
}
})
//if found a movie in local db, return that
if(movieLocal != null){
//Set local to true
movieLocalJson = movieLocal.toJSON()
movieLocalJson.local = true
return res.json(movieLocalJson)
}
//Send the data from MoviesMiniDatabase
res.send(await findOneMoviesMiniDB(movie_id))
};
One feature that would make sense and would make a good challenge is adding the ability for a user to send friend requests to others and view their friend's movie lists.
Smaller features I could add are:
- Custom error page
- Requiring a secure password when registering
- Asking for confirmation when deleting a movie
- Allow the user to select multiple movies for addition/deletion. Allow the user to empty their list at once.
The inspiration came from the Project Ideas List. I liked the MyTop100Movies project idea and implemented my version of it.
The general purpose of this project was for me to learn how to make a full-stack application with a database (CRUD) and user authentication system.
This is currently my biggest project. Working on it has taught me a lot of things and I would not be able to list every single one of them. However here is a brief list of some of the things that I learned:
- How to configure an Express server.
- How to set up server-client communications.
- How to use React Router for client-side routing.
- How to use Passport.js for local authentication.
- How to use Sequelize to create and interact with a database.
- Create database models. Set-up relationships.
- How to configure larger projects (break down the code into separate files and folders)
- Improved CSS skills (navbar and card designs)
Although I had a degree of familiarity with Express and React, a lot of the things were new to me and I had to learn them on the go.
For the technologies that were new to me - like React Router, Sequelize, and Passport.js - I mostly followed the official documentation, along with some community tutorials. These community tutorials were mostly written (I better absorb written information).
Nonetheless, I did find a couple of Web Dev Simplified videos quite useful. Especially for some of the CSS designs and Passport.js authentication.