A Step-by-Step Guide: TODO App using Spring Boot REST & React JS

Sai Tanuj Madisetty
8 min readSep 8, 2021

--

Messy calendar? Time to build a simple TODO application with some of the trendiest tech tools – let’s minimize clutter, shall we?

What you will learn:

  1. How to use Spring Boot with Java to create REST API Endpoints
  2. Creating your own API
  3. How to integrate HSQL with Spring Data JPA
  4. How to use Lombok, Spring Boot & Hibernate Annotations
  5. What Components are in ReactJS (and how to create them)
  6. Fetching from our custom-made API (via axios)
  7. Front-end integration with Back-end Logic
  8. React Bootstrap (Form, Dropdown, Modal, etc.)
  9. Various other React tools (like Router)

Future Add-Ons:

  1. Integrate with mySQL (RDBM)
  2. Testing of our TODO App (via Selenium, Karate, Cucumber)
  3. Security (via Spring Security — OAuth2)
  4. Deployment (via AWS, Heroku, or Azure)

Requirements for this guide:

  1. Basic understanding in Object Oriented Programming — with Java
  2. Basic understanding of APIs, Javascript, HTML

Let’s get started — for real.

Backend

Let’s get started with the Backend — the “end” doing all the main logic to properly interact with our HSQL database as well as provide our REST Endpoints so we can access those from our front end.

What is HSQL?

HSQL, in layman’s terms, is a small and fast in-memory database. In-memory means that we aren’t saving our data in another “app” for later. We are simply saving them in our computer…until we shut down our program and restart for a new session. This means that whenever we restart our program, our data (TODOs) from the last session will be lost. Poof!

What are REST Endpoints?

REST stands for Representational State Transfer. A REST Service Endpoint gives users access to a set of REST resources. REST endpoints also relate to the CRUD operations (create, read, update, and delete) by helping us create requests. Simply, they are the connection to our glorious backend server!

Creating our Spring Boot Project:

  1. Go to https://start.spring.io/
  2. Look at the picture below :)
Select these configuration and add the dependencies shown.

Now, click “Generate” at the bottom. Move the downloaded .zip file to a preferable location. Extract the .zip. Download IntelliJ or an IDE of your choice. Open the extracted folder in the IDE. You’re all set.

<These folders are not necessary for our project.

I would recommend creating packages as shown in the picture: controller, entity, repositories, service. Each of these serve a purpose to integrate our backend.

<<< How you run your backend code!

<<<Config for HSQL goes in one of those files. You might not have the application.yml — don’t worry!

pom.xml? we will be using this ALOT for dependencies.

Concepts we need to understand about this architecture:

  1. Our entity folder just contains POJOs (plain old java objects) like Student or Person. But in our case, it’s Todo or Course.
  2. Our “repositories” folder will contain interfaces which extend the JpaRepository<>. This will be the basis for our data retrieval from the HSQL database (or any database we have chosen). Don’t worry, this will make more sense with the code. This is the “backest” code in the backend. There really isn’t much code in here and it just calls methods from its parent, JpaRepository<>.
  3. The next “backest” layer we have is the service layer. This layer is responsible for calling methods in our repositories.
  4. Lastly, our controller layer. This contains all the REST Endpoints and mappings for URLs to which the frontend will access.

The reason we have all these layers is not only to stay organized, but also, to not allow people to access endpoints and access data unauthorized (another layer or 2 of security.)

Let’s first get our dependencies via our pom.xml file:

Note: some of these dependencies are not necessary, I included them for experimental purposes.

Remember: we need these dependencies for our project to function properly!

Entities:

Let’s create our Entities first. Remember, these are just POJOs, however we can enhance our code by using Lombok and Spring Annotations to skip the boiler-plate code.

Course Entity:

We need the “@Entity” annotation to let Spring Boot know that we are creating an Entity. We are also giving our database table a name with the optional “@Table” annotation. Similarly, we use the “@Column” annotation to give our column in our table a name. Back to the top! If we want, we could write ALL the boiler plate code. But, instead we can use Lombok’s “@Data” annotation to generate all the boilerplate code used in simple POJOs and beans: getters for all attributes, setters for all non-final fields, and appropriate toString, equals and hashCode methods. For our id attribute we need the “@Id” attribute as well as the “@GeneratedValue” to generate ids upon creation of TODOs automatically.

User Entity:

Repeat the same for the User. Do notice the “unique = true” parameter in the “@Column” annotation. We use this to make sure our usernames are unique for all users of our application. Indeed, this is optional.

Repositories:

A repository, as aforementioned, are just interfaces which interacts with its parent to ‘save/retrieve/update/delete’ (CRUD) our entity objects. Naming conventions for our methods are KEY, as that’s how the Spring Data JPA accesses data from our HSQL database! Luckily, they contain minimal code :)

Course repository:

Things to consider:

  1. First things first. We need an @Repository annotation to tell Spring Data that this is a special interface.
  2. We need to extend JpaRepository and inside the <>, we need to put <what entity this repo is based on, the type of the ID field>. Remember from our Course entity, our id field was of type int.
  3. The method names are supposed to follow a specific format. Remember, these methods’ implementations are in the JpaRepository, all we have to do is write the return type followed by the method name. We always start with ‘find’ and we can have ‘All’ afterward if we want to retrieve a list of data from our database. For the first method (findByName), we want to find a TODO by its name (ex. Math Homework). Remember, the return type is our Course entity (or whatever you named your POJO). We simply pass in a ‘name’ attribute and that’s it! For our second method (findAllByUsername), we want to find ALL the todos a specific person has — by using that user’s username. Remember, we have to return a type List here, since we are saying findAll. Both methods perform a GET (CRUD).

User repository:

More things to consider:

  1. If you haven’t noticed, we need to create a repository for every entity we create.
  2. Here, we are using this interface to find/get Users (same name as entity).
  3. In the first ‘GET’ method (findByUsernameAndPassword), we are finding a user based on his/her username AND password, hence the ‘And’ in the method name. If you think about it, this ‘username’ and ‘password’ are attributes in our User entity. We CAN only make methods with the attributes that are defined in our entities. Same goes for ALL our repositories (see CourseRepository.java too)
  4. In the second ‘GET’ method (findTopByUsername), we are finding the first user in our database that has that username. This method becomes useful when we restrict a username per person (so no multiple users with the same username).
  5. The 3rd method is similar to the 2nd. We need a user’s password to check if they are in the database.

Services:

Like our repositories, we will a service for each of our entities (Course/Todo & Entity). This is also where we utilize our Core Java Skills!

Course service:

Even more things to consider:

  1. We need an ‘@Service’ annotation. We also need to use Spring Framework’s handy ‘@Autowired’ so we don’t instantiate a course repository object manually.
  2. Post methods: allow us to add something, in our case a todo. Think of posting a new pic on your social media. In our saveCourse method, we are using JpaRepository’s inbuilt save() method. There’s even a saveAll() method for people who want to save multiple entities (todos) at once.
  3. Get methods: allow us to actually retrieve our info/todos. We created some custom GET methods in our CourseRepository. Some other inbuilt methods include findAll which returns ALL the todos, regardless of person (messy!). We can findById too. If you see the next two GET methods, you see that we are actually accessing the methods in our repository that we created. Once again, keep the return types consistent.
  4. Put methods: allow us to update something, in our case a todo. Think of you updating/editing your comment on Youtube. We only need one of these as there really isn’t multiple ways to update our todo. The user passes in an updated course and we just modify the one that’s already there with simple ‘set’ methods.
  5. Delete methods: allow us to delete our entities, in our case a todo. We need an id and we find our entity using findById and delete that entity.
  6. For all these types of methods, we need our CourseRepository which itself needs a parent, the JpaRepository!

User service:

What’s new with this service?

  1. Everything here is similar to our other service, besides we are auto-wiring our user repository. Here we don’t have an update user/delete user feature — only GET and CREATE.
  2. The getUserByUsername is in charge of checking if a user exists by validating if their username AND password exists in the database. We return a boolean indicating if that user exists.
  3. The findUserByUsername is there to see if a specific username already exists on the database. We need this method to make sure we don’t have users with the same username. You are probably familiar with “please choose another username” on several websites you’ve created.
  4. We have a saveUser method to add users to the database.

Controllers:

Here is where we actually list out our REST Endpoints and URL mappings. The code here is relatively simple and the methods here call the methods from our services we created before. Remember this layer breakdown is necessary not only so it stays organized, but also to add security measures to our project. Again, we need to have controllers for each corresponding service.

Course Controller:

What are the main takeaways?

  1. We need the @CrossOrigins annotation because we need to tell our application that we would receive requests from our front end part of the app which runs on local host port 3000.
  2. Another default annotation is the @RestController.
  3. Get Requests need a @GetMapping annotation, followed by the URL you want with parameters in curly brackets. We use the @PathVariable annotation for the parameters we specified in the URLs (make sure to use the same name for variable as the one defined in the parameter).
  4. Optionally, we can use the @RequestBody annotation for requests that need the page’s content (for example, we need to access the TODO the user enters on to our ‘website’ via the RequestBody annotation.)
  5. Do the same for the rest of the HTTP requests (‘CRUD’).

User Controller:

As you can see, this is very similar to the CourseController.java, except with some minor differences in logic (which is expected since this deals with User Registration.)

Photo by Jason Dent on Unsplash

Awesome, you have finished the backend portion of the application. Take a break if you need one––i’ll catch you in the front end portion (article coming soon)!

--

--