I had been having a tough time to understand Springboot tutorials on creating an API. I know in general they are simple, but why to add more boilerplate and unnecessarily complicate things. All I wanted is to learn and understand the pattern - how things are connected end to end on a very simple data attribute flowing from database to the browser through the Springboot application. So here is what I had learnt, and hope it comes in handy for you.
Steps
Hope you have the prerequisites ready. I have MySQL installed, with a database “employee” with a table named “Employees” with the following data.
+------------+-----------+
| EmployeeID | FirstName |
+------------+-----------+
| 1 | John |
| 2 | Jane |
| 3 | Bob |
+------------+-----------+
1. Base Springboot template
Get the base template to work with from Spring initializer website. This will come with a package com.demo
2. Update application.properties
Configure database connection, preferences on behaviour of the Spring application, and logging of SQL.
# To connect to MySQL database "employee" as root user. My root didn't require a password :)
spring.datasource.url=jdbc:mysql://localhost:3306/employee
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# To avoid casing changes on column names when querying happens --- Take care of this!
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
# To enable SQL logging
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
3. Create ‘Employee’ entity
Create a ‘entity’ package and inside that create a ‘Employee’ class. Each row in the table can be correlated to this entity, hence the mapping between class attributes and the column names in the table.
package com.example.demo.entity; // Inside entity package!
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "Employees") // Maps to `Employees` table row
public class Employee {
@Id
public Long EmployeeID;
public String FirstName;
}
4. Create a ‘EmployeeRepository’ interface
Create a ‘repository’ package and inside that create a ‘EmployeeRepository’ interface. This will provide the methods to perform CRUD (Create / Read / Update / Delete) operations on the table. This repository is connected to ‘Employee’ entity which is connected to ‘Employees’ table. Spring Data JPA automatically creates an implementation of this interface at runtime. So for things you want to customize, you would probably override and provide your own implementation. Else simple CRUD we are good!
package com.example.demo.repository; // Inside repository package!
import com.example.demo.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> { }
5. Create a controller that handles the web requests
package com.example.demo.controller; // Inside controller package!
import com.example.demo.entity.Employee;
import com.example.demo.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class EmployeeController {
@Autowired
private EmployeeRepository employeeRepository;
// Requests on this route are handled
@GetMapping("/")
public List<Employee> getAllEmployees() {
// Spring takes care of initializing 'employeeRepository'
return employeeRepository.findAll();
}
}
Overall, the package/directory structure would look like below. FYI, only Repository file is an interface - as the Spring Data JPA will provide the implementation during runtime.
Spring automatically initializes various components in proper order, and connects them during booting of application using Annotations on each of the classes or interfaces.
@RestController - makes the class a handler for REST API calls
@GetMapping - to handle a specific route
@Autowired - automatically updates / initializes it is on
@Repository - CRUD operations implementor
@Entity - Row mapping of a table
Finally I am able to run the application end to end, and could see the data reflecting on the browser UI.
Let me know your thoughts. Thanks.