The goal of this introduction course is to learn the basics of developing REST APIs using Java and SpringBoot.
- Install IntelliJ Ultimate
- Install Maven
- Install some tool to perform API request (e.g. Postman)
- Install Java 11 (this app is not tested for newer java versions, so compatibility with anything other than java 11 is not guaranteed.)
- REST API
- Dependency injection
- Beans
- RestController
- DTO objects
- JPA
- H2 database
- JUnit
We will create a simple REST API where the end product should be a service where you can create, and view movies displayed at a Cinema.
We will also create some unit tests to verify our application work as intended.
You will find the solution for each exercise in branches named after the exercise number (e.g: ex-1
, ex-2
, ex-2b
, etc...).
It can be a good idea to look for examples in the PowerPoint 💡
- Open the project folder in IntelliJ.
- If IntelliJ asks it you want to install dependencies, hit yes. If not open the built-in terminal and run
mvn clean install
. - Run the spring application with one of the following methods:
- Open CinemaApplication.java and hit the green play button to the left of the code.
- run
mvn spring-boot:run
in the terminal.
Create a Controller - solution branch: ex-1
We should now create our first API endpoint 🙌
- Create a new Java class which will function as our REST Controller class, using the annotations:
@RestController
and@RequestMapping
at the class level with the following endpoint:/movies
. - Now add one method for a GET request using the
@GetMapping
annotation. The method should only return a String. - Run the application and open your web browser. Go to the following URL: localhost:8080/movies. You should now see the String you wrote in the Controller Class, in your browser window.
Note that the endpoint paths doesn't need to be set at the class level. You can define paths on each method in the class, but they will be sub-paths under the class path.
!!!! Remember to restart the application between every code change. !!!!
Create a Service class using @Bean
- solution branch: ex-2
- Create a normal java class called
MovieService
. This should have a field variable which should contain a list of movie titles (as Strings) and a method that returns the list of movie titles. I will call this methodgetMovies
. - Now we need a bean (instantiated object of
MovieService
). Go to theCinemaApplication
-class and here you should create a bean that returns aMovieService
object. - In the controller class, create a field variable of the
MovieService
. Instantiate the field variable using the@Autowired
annotation.-
This way spring will find the bean (instance) of
MovieService
we created in step 2 and inject it here in the controller class.
-
- Inside the
@GetMapping
method in the Controller class, use theMovieService
field variable to call the method that returns the list of movies, and make the Controller method return that list (remember to update the return type). - Your API should now return a list of Movie titles.
Create a Service class using @Service
- solution branch: ex-2b
- Annotate the
MovieService
class with@Service
. Now we can remove the bean created in theCinemaApplication
-class. - Test the API endpoint again.
Create a Movie DTO (Data transfer object) - solution branch: ex-3
- Create a class called MovieDto.
- Create two field variables with getters and setters:
title
(String) andageLimit
(of typeInteger
notint
to avoid NullPointerException). - Create a constructor that can accept and set both field variables.
- Create two field variables with getters and setters:
- In the
MovieService
class change the return type of thegetMovie
method to a list MovieDto objects. - Also in the
MovieService
class, populate the previously created list of strings (Movie titles) with new MovieDto objects instead. - You will now see that by calling your API, that Spring automatically serializes the java objects (MovieDto) into JSON objects.
Now we want to create new Movies by doing an HTTP POST request to our API. By doing a POST request a new movie should be added in the list of MovieDtos:
- Create a new method in
MovieService
calledaddMovie
, which takes in a MovieDto object as a parameter and adds it into our list of MovieDtos. - Create a new method in the Controller class, call it
createMovie
. This should handle a POST request (you can guess the annotation we need 🙌).- Add the newly created MovieDto class as a parameter to the new
createMovie
method. - To make spring recognise the parameter as a http request body, annotate the parameter with
@RequestBody
. - Call the new
addMovie
method inMovieService
and pass along the MovieDto object.
- Add the newly created MovieDto class as a parameter to the new
- Use Postman or Curl to perform a POST request to our API with a JSON object representing a MovieDto object in the request body.
We will now see that Spring automatically deserializes the JSON object into a Java class, and when calling the GET endpoint we will see the new movie object in the response.
Make use of a database and create entity classes - solution branch: ex-4
Now we will make use of an H2 database (in-memory-database).
It's best practise not to use entity objects as request body in controllers, and instead convert from Dto's to Entity objects before sending data to the database. You should also convert entity objects to DTO's before returning them to the user.
- Create an entity class called
Movie
(this will represent a table in our database).- The new
Movie
class should contain the same fields as the MovieDto class, but should have one more field variable:id
. - Create an empty (default) constructor. You can also create a constructor that takes in parameters, but you need an empty constructor anyways. Note that you should never set the value of the
id
field.
- The new
- The id should be our Primary key (
@Id
), and should be auto generated (@GeneratedValue
). - Create a new java Interface which should be annotated with the
@Repository
annotation. This will enable us to communicate with our database.- In the Interface extend CrudRepository and use our entity class and primary key type (
Integer
) in combination with CrudRepository. This is to make it possible to communicate with theMovie
table.
- In the Interface extend CrudRepository and use our entity class and primary key type (
- In the
MovieService
class, we will now make use of a database instead of the previously created list of MovieDto's:- Remove the list of movies in
MovieService
. - Autowire the new repository interface as a field variable.
- In the
addMovie
, convert the incomingMoviceDto
object to aMovie
-entity object (remember not to set theid
property). Use the repository interface variable to save theMovie
-entity object to the database. - In the
getMovie
, use the repository interface field variable to query the database for all movies. Convert theMovie
-entity objects toMoviceDto's
and return all theMoviceDto's
.
- Remove the list of movies in
- The database will now be empty each time you restart your application so test that you can create a new movie by doing a POST and GET request.
View movies in our database - solution branch: ex-4b
We will now use the h2 console to view the data stored in our database.
-
To enable the H2 console paste in the following in your application.yml file:
spring: h2: console: enabled: true path: /h2-console
-
Restart the application.
-
Look for a terminal output that says the following:
H2 console available at '/h2-console'. Database available at
and copy the database URL (looking something like this:jdbc:h2:mem:XXXXX
) -
Open the H2 console by going to this url http://localhost:8080/h2-console.
-
Replace the JDBC URL with the one you copied in step 2.
-
The username should be:
sa
-
Let the password field be empty.
-
Hit Connect and navigate the database.
Create our first unit test and populate test database with data - solution branch: ex-5
We will use the test class already generated in the test folder.
- Autowire the
MovieService
class as a field variable. - Create your own test method or use the one that already exist, just make sure to annotate each test method with
@Test
. - In the test method use
MovieService
to retrieve the number of objects in the database. Then useMovieService
to create a new movie. - Compare the number of objects in the database using
assertTrue
,assertFalse
or whatever "assert" you think work the best.
- Create a configuration (
@Configuration
) class in the test folder that will populate our database with some test data. - Make it possible to query moves by their age limit using query parameters on the
@GetMapping
method and implement the necessary logic. - Create a new endpoint to delete a movie from the database.