RESTful Tutorial with Java 25 and Spring Boot

🚀 Building RESTful Services with Java 25 & Spring Boot — A Complete Guide


1. What is a RESTful Service?


REST (Representational State Transfer) is an architectural style for designing networked applications. A RESTful service:

  • Exposes resources via URLs

  • Uses HTTP methods (GET, POST, PUT, DELETE, PATCH)

  • Is stateless

  • Exchanges representations (mostly JSON)

  • Uses standard HTTP status codes

  • Follows resource-oriented design


Example Resources

GET    /api/employees        -> Get all employees
GET    /api/employees/1      -> Get employee by id
POST   /api/employees        -> Create employee
PUT    /api/employees/1      -> Update employee
DELETE /api/employees/1      -> Delete employee

2. Tech Stack

  • Java 25

  • Spring Boot 3.x+ (latest)

  • Spring Web

  • Spring Validation

  • Spring Data JPA (optional for DB)

  • Jackson (JSON serialization)

  • Maven or Gradle

  • H2 / PostgreSQL (optional)


3. Project Structure (Typical)

com.example.demo
 ├── DemoApplication.java
 ├── controller
 │    └── EmployeeController.java
 ├── service
 │    └── EmployeeService.java
 ├── repository
 │    └── EmployeeRepository.java
 ├── model
 │    └── Employee.java
 ├── dto
 │    └── EmployeeRequest.java
 └── exception
      ├── GlobalExceptionHandler.java
      └── ResourceNotFoundException.java


4. Maven Dependencies (Key Ones)

  • spring-boot-starter-web

  • spring-boot-starter-validation

  • spring-boot-starter-data-jpa

  • h2 or postgresql

  • lombok (optional)


5. The Main Application

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

🔍 Annotation Explained

  • @SpringBootApplication = Combines:

    • @Configuration → Marks as config class

    • @EnableAutoConfiguration → Auto configures Spring Boot

    • @ComponentScan → Scans components in package


6. The Entity (Model)

@Entity
@Table(name = "employees")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    private String department;

    private double salary;

    // getters and setters
}

🔍 Annotations Explained

  • @Entity → Marks class as JPA entity

  • @Table → Maps to DB table

  • @Id → Primary key

  • @GeneratedValue → Auto ID generation

  • @Column → Column mapping & constraints


7. DTO for Request Validation

public class EmployeeRequest {

    @NotBlank
    private String name;

    @NotBlank
    private String department;

    @Positive
    private double salary;

    // getters and setters
}

🔍 Validation Annotations

  • @NotBlank → Must not be null/empty

  • @Positive → Must be > 0

  • Works with @Valid in controller


8. Repository Layer

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}

🔍 Annotations Explained

  • @Repository → Marks DAO layer, enables exception translation

  • JpaRepository → Gives CRUD, paging, sorting out-of-the-box


9. Service Layer

@Service
public class EmployeeService {

    private final EmployeeRepository repository;

    public EmployeeService(EmployeeRepository repository) {
        this.repository = repository;
    }

    public List<Employee> getAll() {
        return repository.findAll();
    }

    public Employee getById(Long id) {
        return repository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Employee not found"));
    }

    public Employee create(Employee employee) {
        return repository.save(employee);
    }

    public Employee update(Long id, Employee updated) {
        Employee existing = getById(id);
        existing.setName(updated.getName());
        existing.setDepartment(updated.getDepartment());
        existing.setSalary(updated.getSalary());
        return repository.save(existing);
    }

    public void delete(Long id) {
        repository.deleteById(id);
    }
}

🔍 Annotations Explained

  • @Service → Marks business logic layer

  • Helps with separation of concerns


10. REST Controller (Core of REST API)

@RestController
@RequestMapping("/api/employees")
public class EmployeeController {

    private final EmployeeService service;

    public EmployeeController(EmployeeService service) {
        this.service = service;
    }

    @GetMapping
    public List<Employee> getAll() {
        return service.getAll();
    }

    @GetMapping("/{id}")
    public Employee getById(@PathVariable Long id) {
        return service.getById(id);
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Employee create(@Valid @RequestBody EmployeeRequest request) {
        Employee emp = new Employee();
        emp.setName(request.getName());
        emp.setDepartment(request.getDepartment());
        emp.setSalary(request.getSalary());
        return service.create(emp);
    }

    @PutMapping("/{id}")
    public Employee update(@PathVariable Long id, @Valid @RequestBody EmployeeRequest request) {
        Employee emp = new Employee();
        emp.setName(request.getName());
        emp.setDepartment(request.getDepartment());
        emp.setSalary(request.getSalary());
        return service.update(id, emp);
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable Long id) {
        service.delete(id);
    }
}


11. Controller Annotations — Deep Dive

  • @RestController

    • = @Controller + @ResponseBody

    • Returns JSON directly

  • @RequestMapping("/api/employees")

    • Base URL mapping for controller

  • @GetMapping, @PostMapping, @PutMapping, @DeleteMapping

    • Shortcut for @RequestMapping(method = ...)

  • @PathVariable

    • Extracts value from URL path

  • @RequestBody

    • Converts JSON → Java object

  • @ResponseStatus

    • Sets HTTP status code

  • @Valid

    • Triggers bean validation


12. Exception Handling (Global)

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Map<String, String> handleNotFound(ResourceNotFoundException ex) {
        return Map.of("error", ex.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Map<String, String> handleValidation(MethodArgumentNotValidException ex) {
        return Map.of("error", "Validation failed");
    }
}

🔍 Annotations Explained

  • @RestControllerAdvice → Global exception handler for REST

  • @ExceptionHandler → Handles specific exception

  • @ResponseStatus → Sets HTTP status


13. HTTP Status Codes (Best Practice)

  • 200 OK → Successful GET/PUT

  • 201 CREATED → Resource created

  • 204 NO CONTENT → Successful DELETE

  • 400 BAD REQUEST → Validation error

  • 404 NOT FOUND → Resource not found

  • 500 INTERNAL SERVER ERROR → Server crash


14. JSON Serialization (Jackson)


Spring Boot automatically:

  • Converts Java → JSON

  • Converts JSON → Java

    Using Jackson


You can control it with:

  • @JsonIgnore

  • @JsonProperty

  • @JsonInclude


15. REST Best Practices


✅ Use nouns, not verbs in URLs

✅ Use proper HTTP methods

✅ Return correct status codes

✅ Use DTOs for requests/responses

✅ Validate input

✅ Version your APIs (/api/v1/...)

✅ Use pagination for large lists

✅ Use proper error responses


16. Testing Endpoints (cURL Examples)

GET    /api/employees
POST   /api/employees
PUT    /api/employees/1
DELETE /api/employees/1

POST body:

{
  "name": "Ravi",
  "department": "Engineering",
  "salary": 120000
}


17 Why Java 25 + Spring Boot?

  • 🔥 Virtual Threads (Project Loom) for massive concurrency

  • ⚡ Faster startup & lower memory

  • 🧠 Better GC & performance

  • 🛠️ Mature ecosystem

  • 🏢 Enterprise-ready

Comments

Popular posts from this blog

Java 10 and 10 Big Java Milestones

Java 21 Features With Example

Kalculate next vesion