Day 2: Building on Our First Endpoints


Welcome back to our Spring Boot learning journey! In Day 1, we set up a Spring Boot project using Spring Initializr and created basic endpoints using @Controller without leveraging @RestController. Today, we’ll enhance our application by introducing @RestController, creating more sophisticated endpoints, and exploring Spring Boot’s dependency injection and configuration features. Let’s dive in!
Prerequisites
A Spring Boot project initialized with Spring Initializr (from Day 1).
Basic understanding of Spring annotations like @Controller and @RequestMapping.
Maven or Gradle installed (depending on your project setup).
An IDE like IntelliJ IDEA or VS Code.
Recap: Day 1 Setup
In Day 1, we:
Used Spring Initializr to create a project with dependencies like Spring Web.
Created a simple endpoint using @Controller to return data, such as a JSON string or plain text, without @RestController.
Tested our endpoint using tools like Postman or a browser.
Our Day 1 controller might have looked like this:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MyController {
@RequestMapping("/hello")
@ResponseBody
public String sayHello() {
return "Hello, Spring Boot!";
}
}
The @ResponseBody annotation ensured the return value was sent directly as the response body, mimicking REST-like behavior. Today, we’ll simplify this using @RestController and add more functionality.
Step 1: Upgrading to @RestController
The @RestController annotation combines @Controller and @ResponseBody, making it ideal for RESTful APIs where responses are typically JSON or XML. Let’s refactor our controller.
Refactored Controller
Replace the Day 1 controller with a @RestController:
package com.example.demo;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
@RestController
@RequestMapping("/api")
public class MyRestController {
@RequestMapping("/hello")
public String sayHello() {
return "Hello from REST Controller!";
}
}
What Changed?
Replaced @Controller with @RestController.
Added @RequestMapping("/api") at the class level to prefix all endpoints with /api.
Removed @ResponseBody since @RestController implicitly applies it to all methods.
The endpoint is now accessible at /api/hello.
Test this by running your application (mvn spring-boot:run or via your IDE) and visiting http://localhost:8080/api/hello. You should see "Hello from REST Controller!".
Step 2: Creating a Data Model
To make our API more useful, let’s create a simple data model and return it as JSON. Create a User class:
package com.example.demo;
public class User {
private Long id;
private String name;
private String email;
// Constructor
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Step 3: Adding a New Endpoint
Let’s add an endpoint to return a User object as JSON. Update the MyRestController:
package com.example.demo;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
@RestController
@RequestMapping("/api")
public class MyRestController {
@RequestMapping("/hello")
public String sayHello() {
return "Hello from REST Controller!";
}
@GetMapping("/user")
public User getUser() {
return new User(1L, "John Doe", "john@example.com insurgent");
}
}
Key Points:
Used @GetMapping instead of @RequestMapping for clarity (specifies HTTP GET method).
Spring Boot automatically serializes the User object to JSON using Jackson (included with Spring Web).
Test the endpoint at http://localhost:8080/api/user. You should see:
{ "id": 1, "name": "John Doe", "email": "john@example.com" }
Step 4: Dependency Injection with @Service
To demonstrate Spring’s dependency injection, let’s create a service to handle user data. Create a UserService class:
package com.example.demo;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public User getUserById(Long id) {
// Simulated data; in a real app, this might query a database
return new User(id, "User " + id, "user" + id + "@example.com");
}
}
Update MyRestController to use this service:
package com.example.demo;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.beans.factory.annotation.Autowired;
@RestController
@RequestMapping("/api")
public class MyRestController {
@Autowired
private UserService userService;
@RequestMapping("/hello")
public String sayHello() {
return "Hello from REST Controller!";
}
@GetMapping("/user")
public User getUser() {
return userService.getUserById(1L);
}
}
What’s Happening?
@Service marks UserService as a Spring-managed bean.
@Autowired injects the UserService instance into the controller.
The endpoint now delegates to the service, promoting separation of concerns.
Test /api/user again; the output should be similar, but now the data comes from the service.
Step 5: Configuring Application Properties
Spring Boot allows customization via application.properties (or application.yml). Let’s set a custom server port and application name. In src/main/resources/application.properties, add:
server.port=8081
spring.application.name=MySpringBootApp
Restart the application and access endpoints at http://localhost:8081/api/....
What’s Next?
In Day 3, we’ll explore:
Connecting to a database using Spring Data JPA.
Handling HTTP methods like POST, PUT, and DELETE.
Adding validation to our endpoints.
Conclusion
Today, we upgraded our Day 1 project by introducing @RestController, creating a data model, using dependency injection with @Service, and configuring basic application properties. Our API is now more structured and ready for further enhancements. Try adding more endpoints or experimenting with query parameters!
Happy coding, and see you in Day 3!
Subscribe to my newsletter
Read articles from Prathamesh Karatkar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
