CodeGym /Courses /Module 5. Spring /Practice: creating a simple REST API to work with entitie...

Practice: creating a simple REST API to work with entities

Module 5. Spring
Level 10 , Lesson 5
Available

Let's put what we've learned into practice and build a REST API to work with entities.

Step-by-step plan to create a REST API

In this lecture we'll create a REST API to manage "User" entities. We'll start by creating a Spring Boot project and implement a CRUD (Create, Read, Update, Delete) API step by step.

1. Creating a Spring Boot project

First, we'll need a new Spring Boot project.

Use Spring Initializr:

  1. Go to Spring Initializr.
  2. Set the following options:
    • Project: Maven
    • Language: Java
    • Spring Boot: 2.x.x (or newer)
    • Dependencies: Spring Web, Spring Data JPA, H2 Database (or another), Lombok (optional but handy).
  3. Download and unzip the project.

2. Configuring application.properties

First, configure the database. In src/main/resources/application.properties set the connection parameters for H2 Database:


# H2 Database configuration
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true

We're using H2 — an embedded database for simplicity during development. If you want to use another database, like PostgreSQL, you'll need to make the appropriate changes.

3. Creating the User entity

Time to get to work. First, define the User entity which will represent a user in our system.


package com.example.demo.entity;

import jakarta.persistence.*;
import lombok.Data;

@Data // Lombok annotation to auto-generate getters/setters
@Entity // Marks the class as a JPA entity
@Table(name = "users") // Specifies the table name
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // Auto-generate ID
    private Long id;

    @Column(nullable = false) // Field cannot be null
    private String name;

    @Column(nullable = false, unique = true) // Unique email
    private String email;

    @Column(nullable = false)
    private Integer age;
}

4. Creating the JPA repository

Now create a repository to interact with the database.


package com.example.demo.repository;

import com.example.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

// JpaRepository provides ready-to-use methods for DB operations
public interface UserRepository extends JpaRepository<User, Long> {
}

5. Creating the REST controller

Now for the fun part — implementing the REST API! Let's create a controller that will handle CRUD operations for User entities.

Example code:


package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController // Marks the class as a REST controller
@RequestMapping("/api/users") // Base path for all endpoints
public class UserController {

    private final UserRepository userRepository;

    // Inject dependency via constructor
    public UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // Get all users (GET /api/users)
    @GetMapping
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    // Get a single user by ID (GET /api/users/{id})
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return userRepository.findById(id)
                .map(ResponseEntity::ok) // If user is found
                .orElse(ResponseEntity.notFound().build()); // If not found
    }

    // Create a new user (POST /api/users)
    @PostMapping
    public User createUser(@RequestBody User user) {
        return userRepository.save(user);
    }

    // Update an existing user (PUT /api/users/{id})
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User updatedUser) {
        return userRepository.findById(id)
                .map(user -> {
                    user.setName(updatedUser.getName());
                    user.setEmail(updatedUser.getEmail());
                    user.setAge(updatedUser.getAge());
                    return ResponseEntity.ok(userRepository.save(user));
                })
                .orElse(ResponseEntity.notFound().build());
    }

    // Delete a user (DELETE /api/users/{id})
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        return userRepository.findById(id)
                .map(user -> {
                    userRepository.delete(user);
                    return ResponseEntity.noContent().build();
                })
                .orElse(ResponseEntity.notFound().build());
    }
}
Note:
Methods return ResponseEntity so the client can get the correct HTTP status code (for example, 404 if the user isn't found).

6. Testing the API

Now let's test our API. You can use a tool like Postman to send requests.

Request examples:

  1. GET /api/users — get all users.
  2. POST /api/users — create a user. Example request body:
    
    {
        "name": "Ivan Ivanov",
        "email": "ivan@example.com",
        "age": 25
    }
    
  3. GET /api/users/1 — get the user with ID = 1.
  4. PUT /api/users/1 — update a user. Example request body:
    
    {
        "name": "Ivan Petrov",
        "email": "petrov@example.com",
        "age": 30
    }
    
  5. DELETE /api/users/1 — delete the user with ID = 1.

7. Possible issues and how to fix them

Issue: the email field isn't unique

If you try to add two users with the same email, you'll get a DB error. To prevent this, add a data pre-check (for example, check if the email already exists before creating the user).

Issue: validation

Right now the data isn't validated. For example, you can create a user with an empty name. We'll fix this later using the @Valid annotation.

Issue: serialization errors

If an object contains references to other entities with cyclic dependencies, Jackson might throw an error. Fix: use the @JsonIgnore annotation (we'll come back to this later).


8. Applying this in real projects

The REST API we built in this lecture is the foundation of any modern application. You can use this approach to manage entities like products, orders, employees, and more. These skills are essential for working as a Java developer, especially in web apps and microservices.

Now you know how to create a REST API from scratch. In the next lecture we'll look at how to design URIs properly and work with resources so your API becomes convenient and professional.

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION