MovieAPI is a backend application built using Spring Boot, Java, and MySQL. It provides RESTful APIs for managing movies, including adding, updating, deleting, and retrieving movie details. It also features user authentication and JWT-based authorization.
- Upload and store movie images.
- Create, update, and delete movies.
- Fetch details of individual movies or a list of all movies.
- User authentication with JWT tokens.
- Password reset and recovery functionality.
- Java: Backend language.
- Spring Boot: Application framework for building microservices.
- MySQL: Database to store movie and user data.
- JWT (JSON Web Tokens): Securing API endpoints.
- Maven: Dependency management.
API Documentation Website url -https://walnut-wrist-9da.notion.site/Movie-API-Documentation-8258fc33d572475384e9199e9deba52a
- URL:
http://localhost:8080/api/v1/auth/register
- Method:
POST
- Description: Registers a new user.
- Request Body:
{ "name": "Sandesh Bhujbal", "username": "sandesh", "email": "[email protected]", "password": "12345" }
- Response:
{ "message": "User registered successfully!" }
- URL:
http://localhost:8080/api/v1/auth/login
- Method:
POST
- Description: Authenticates the user and returns a JWT token.
- Request Body:
{ "email": "[email protected]", "password": "12345" }
- Response:
{ "accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbkBnbWFpbC5jb20iLCJpYXQiOjE3MjY0MDg4MzAsImV4cCI6MTcyNjQwODg1NX0.LIdT4456XO8P40GGCRmylhG0K6NUOjie12joxW6I-3I", "refreshToken": "d4a563b7-98b2-4e16-abcb-3bcb0f05d5bf" }
- URL:
http://localhost:8080/api/v1/auth/refresh
- Method:
POST
- Description: Generates a new access token using the refresh token.
- Request Body:
{ "refreshToken": "d4a563b7-98b2-4e16-abcb-3bcb0f05d5bf" }
- Response:
{ "accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbkBnbWFpbC5jb20iLCJpYXQiOjE3MjY0MDg5OTMsImV4cCI6MTcyNjQwOTAxOH0.bhZWLkNnq0Kza8zgs3WH-dnKSYJteA_wfQuBkppGWXk", "refreshToken": "98b4efd1-9a60-48cb-bb85-bb456ed72e0a" }
- URL:
http://localhost:8080/file/upload
- Method:
POST
- Description: Uploads a movie image.
- Request:
file
: Multipart file upload (image).
- Response:
{ "message": "File uploaded: avengers_endgame1.png" }
- URL:
http://localhost:8080/api/v1/movie/add-movie
- Method:
POST
- Description: Adds a new movie.
- Request (Multipart FormData):
file
: Multipart file upload (movie poster).movieDto
: JSON string with movie details:
{ "movieId": 4, "title": "Jawan", "director": "Rohit Shetty", "studio": "Bollywood", "movieCast": ["Shahrukh Khan", "Priyanka Chopra"], "releaseYear": 2023, "poster": "default.png", "posterUrl": "url" }
- Response:
{ "movieId": 4, "title": "Jawan", "director": "Rohit Shetty", "studio": "Bollywood", "movieCast": ["Shahrukh Khan", "Priyanka Chopra"], "releaseYear": 2023, "poster": "jawan.png", "posterUrl": "http://localhost:8080/file/jawan.png" }
- URL:
http://localhost:8080/api/v1/movie/{id}
- Method:
GET
- Description: Retrieves details of a specific movie by its ID.
- Response:
{ "movieId": 2, "title": "Animal", "director": "Sandeep Vanga", "studio": "Bollywood", "movieCast": ["Ranbir Kapoor", "Rashmika Mandanna", "Tripti Dimri"], "releaseYear": 2023, "poster": "animal.png", "posterUrl": "http://localhost:8080/file/animal.png" }
- URL:
http://localhost:8080/api/v1/movie/all
- Method:
GET
- Headers:
Authorization
: Bearer token.
- Description: Retrieves a list of all movies.
- Response:
[ { "movieId": 2, "title": "Animal", "director": "Sandeep Vanga", "studio": "Bollywood", "movieCast": [ "Ranbir Kapoor", "Rashmika Mandanna", "Tripti Dimri" ], "releaseYear": 2023, "poster": "animal.png", "posterUrl": "http://localhost:8080/file/animal.png" }, { "movieId": 3, "title": "flash-2", "director": "Sandeep Vanga", "studio": "Hollywood", "movieCast": [ "Salaman Khan", "Rashmika Mandanna", "Tripti Dimri" ], "releaseYear": 2024, "poster": "flash.png", "posterUrl": "http://localhost:8080/file/flash.png" }, { "movieId": 4, "title": "jawan", "director": "Rohit shetty", "studio": "Bollywood", "movieCast": [ "Shahrukh khan", "Priyanka Chopra" ], "releaseYear": 2023, "poster": "jawan.png", "posterUrl": "http://localhost:8080/file/jawan.png" } ]
- URL:
http://localhost:8080/api/v1/movie/update/{id}
- Method:
PUT
- Description: Updates details of an existing movie.
- Request (Multipart FormData):
file
: Multipart file upload (new movie poster).movieDtoObj
: JSON string with updated movie details:
{ "movieId": 2, "title": "Animal", "director": "Sandeep Vanga, Rohit Shetty", "studio": "Bollywood", "movieCast": ["Ranbir Kapoor", "Rashmika Mandanna", "Tripti Dimri", "Bobby Deol"], "releaseYear": 2023, "poster": "default.png", "posterUrl": "url" }
- Response:
{ "movieId": 2, "title": "Animal", "director": "Sandeep Vanga, Rohit Shetty", "studio": "Bollywood", "movieCast": ["Ranbir Kapoor", "Rashmika Mandanna", "Tripti Dimri", "Bobby Deol"], "releaseYear": 2023, "poster": "animal.png", "posterUrl": "http://localhost:8080/file/animal.png" }
- URL:
http://localhost:8080/api/v1/movie/delete/{id}
- Method:
DELETE
- Description: Deletes a movie by its ID.
- Response:
{ "message": "Movie deleted with id = 3" }
- URL:
http://localhost:8080/forgotPassword/verifyMail/{email}
- Method:
POST
- Description: Sends an OTP to the user's email for password reset.
- Response:
{ "message": "Email sent for verification!" }
- URL:
http://localhost:8080/forgotPassword/verifyOtp/{otp}/{email}
- Method:
POST
- Description: Verifies the OTP for password reset.
- Response:
{ "message": "OTP verified!" }
- URL:
http://localhost:8080/forgotPassword/changePassword/{email}
- Method:
POST
- Request Body:
{ "password": "123456", "repeatPassword": "123456" }
- Description: Changes the user's password after OTP verification.
- Response:
{ "message": "Password has been changed!" }
-
Clone the Repository:
git clone https://https://github.com/sandesh300/Movie-API.git
-
Navigate to the Project Directory:
cd MovieAPI
-
Configure MySQL:
- Create a database named
movies_db
. - Update the
application.properties
file with your MySQL configurations.
- Create a database named
-
Build the Project:
mvn clean install ``
This section documents the unit tests for the Movie Module, covering core functionalities such as adding a movie, updating a movie, get all movies, get movie by id, deleting a movie.
Ensure the following setup is complete before running the tests:
- JUnit 5: Tests are written using JUnit 5.
- Mockito: Used for mocking dependencies in services and repositories.
- Spring Boot Test: Provides support for integration testing in Spring Boot applications.
To run the tests, use:
mvn test
Or in IntelliJ, right-click on the test file and select Run 'Tests'.
This test case verifies that the addMovie
API correctly creates a new movie and returns the expected movie details.
@Test
public void shouldCreateMovieWhenValidRequest() throws IOException {
// Given: A MovieDto object with valid data and a MultipartFile
MovieDto movieDto = new MovieDto(null, "Inception", "Christopher Nolan", "Warner Bros.", Set.of("Leonardo DiCaprio", "Joseph Gordon-Levitt"), 2010, "inception-poster.png", null);
MultipartFile file = new MockMultipartFile("file", "inception-poster.png", "image/png", "dummy content".getBytes());
// Mock: Simulate the file upload and movie creation process
String uploadedFileName = "inception-poster.png";
when(fileService.uploadFile(anyString(), any(MultipartFile.class))).thenReturn(uploadedFileName);
Movie savedMovie = new Movie(1, movieDto.getTitle(), movieDto.getDirector(), movieDto.getStudio(), movieDto.getMovieCast(), movieDto.getReleaseYear(), uploadedFileName);
when(movieService.addMovie(any(MovieDto.class), any(MultipartFile.class))).thenReturn(movieDto);
// When: The controller's addMovie method is called
ResponseEntity<MovieDto> response = movieController.addMovie(file, new ObjectMapper().writeValueAsString(movieDto));
// Then: Assert that the response is CREATED and the movie details match the expected data
assertEquals(HttpStatus.CREATED, response.getStatusCode());
assertEquals(movieDto.getTitle(), response.getBody().getTitle());
assertEquals(movieDto.getDirector(), response.getBody().getDirector());
assertTrue(response.getBody().getPoster().endsWith(".png")); // Ensure the poster filename ends with .png
}
- Explanation:
- Given: Prepare a valid
MovieDto
and a mock file. - When: Call the controller's method to add a movie.
- Then: Verify the response status and the content of the returned movie.
- Given: Prepare a valid
This test case checks that the updateMovie
API updates an existing movie's details correctly.
@Test
public void shouldUpdateMovieWhenValidRequestWithPngFile() throws IOException {
// Given: An existing movie ID and an updated MovieDto object with a PNG file
Long movieId = 1L;
MovieDto updatedMovieDto = new MovieDto(movieId, "Inception", "Christopher Nolan", "Warner Bros.", Set.of("Leonardo DiCaprio", "Joseph Gordon-Levitt"), 2010, "inception-updated-poster.png", null);
MultipartFile file = new MockMultipartFile("file", "inception-updated-poster.png", "image/png", "dummy content".getBytes());
// Mock: Simulate file upload and movie update process
String updatedFileName = "inception-updated-poster.png";
when(fileService.uploadFile(anyString(), any(MultipartFile.class))).thenReturn(updatedFileName);
Movie updatedMovie = new Movie(movieId, updatedMovieDto.getTitle(), updatedMovieDto.getDirector(), updatedMovieDto.getStudio(), updatedMovieDto.getMovieCast(), updatedMovieDto.getReleaseYear(), updatedFileName);
when(movieService.updateMovie(eq(movieId), any(MovieDto.class), any(MultipartFile.class))).thenReturn(updatedMovieDto);
// When: The controller's updateMovie method is called
ResponseEntity<MovieDto> response = movieController.updateMovie(movieId, file, new ObjectMapper().writeValueAsString(updatedMovieDto));
// Then: Assert that the response is OK and the movie details match the updated data
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(updatedMovieDto.getTitle(), response.getBody().getTitle());
assertEquals(updatedMovieDto.getPoster(), response.getBody().getPoster());
}
- Explanation:
- Given: An existing movie ID and updated movie details.
- When: Call the controller's method to update the movie.
- Then: Verify that the response status is OK and the updated movie details are correct.
This test case verifies that the getAllMovies
API correctly retrieves a list of all movies.
@Test
public void shouldReturnAllMovies() {
// Given: A list of movies
List<MovieDto> movieDtos = Arrays.asList(
new MovieDto(1L, "Inception", "Christopher Nolan", "Warner Bros.", Set.of("Leonardo DiCaprio", "Joseph Gordon-Levitt"), 2010, "inception-poster.png", "http://localhost/file/inception-poster.png"),
new MovieDto(2L, "The Dark Knight", "Christopher Nolan", "Warner Bros.", Set.of("Christian Bale", "Heath Ledger"), 2008, "dark-knight-poster.png", "http://localhost/file/dark-knight-poster.png")
);
when(movieService.getAllMovies()).thenReturn(movieDtos);
// When: The controller's getAllMovies method is called
ResponseEntity<List<MovieDto>> response = movieController.getAllMoviesHandler();
// Then: Assert that the response is OK and contains the list of movies
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(movieDtos.size(), response.getBody().size());
assertEquals("Inception", response.getBody().get(0).getTitle());
assertEquals("The Dark Knight", response.getBody().get(1).getTitle());
}
- Explanation:
- Given: A predefined list of movies.
- When: Call the controller's method to get all movies.
- Then: Verify the response status and ensure the list contains the expected movies.
This test case verifies that the getMovieById
API works as expected and returns the correct movie details for a valid movie ID.
@Test
public void shouldReturnMovieWhenMovieIdExists() {
// Given: A valid movie ID
Long movieId = 1L;
// Mock: Simulating the expected Movie object that should be returned by the service
Movie mockMovie = new Movie(movieId, "Inception", "A mind-bending thriller", 2010);
when(movieService.getMovieById(movieId)).thenReturn(Optional.of(mockMovie));
// When: The controller's getMovieById method is called
ResponseEntity<Movie> response = movieController.getMovieById(movieId);
// Then: Assert that the response is OK and the movie returned matches the expected data
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(mockMovie.getTitle(), response.getBody().getTitle());
assertEquals(mockMovie.getYear(), response.getBody().getYear());
}
- Explanation:
- Given: We prepare a movie ID and mock the service to return the movie with that ID.
- When: The controller is invoked to fetch movie details.
- Then: We validate the response status and content.
This test case verifies that the deleteMovie
API correctly deletes a movie by its ID.
@Test
public void shouldDeleteMovieWhenMovieIdExists() {
// Given: A valid movie ID to be deleted
Long movieId = 1L;
// Mock: Simulating the behavior of the movieService to delete the movie
doNothing().when(movieService).deleteMovie(movieId);
// When: The controller's deleteMovie method is called
ResponseEntity<Void> response = movieController.deleteMovie(movieId);
// Then: Assert that the response status is NO_CONTENT (204) indicating successful deletion
assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
// Verify that the movieService's deleteMovie method was called exactly once
verify(movieService, times(1)).deleteMovie(movieId);
}
- Explanation:
- Given: A movie ID is passed for deletion, and the service's delete behavior is mocked.
- When: The controller is called to delete the movie.
- Then: We ensure the correct status is returned and the service is called exactly once.
- Mocking: Use Mockito to mock services and file uploads to isolate the controller logic from actual service implementations.
- Edge Cases: Consider writing tests for edge cases such as invalid inputs, missing data, or failure scenarios to ensure robustness.