← Назад к вопросам

Как написать RESTful приложение для чтения данных из базы данных

2.2 Middle🔥 241 комментариев
#REST API и микросервисы#Spring Framework#ООП

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как написать RESTful приложение для чтения данных из базы данных

Расскажу полный пример создания RESTful приложения с соблюдением best practices.

1. Domain Layer

@Value
public class User {
    Long id;
    String email;
    String name;
    int age;
    
    public boolean isAdult() {
        return age >= 18;
    }
}

public interface UserRepository {
    Optional<User> findById(Long id);
    List<User> findAll();
    Page<User> findAllPaged(int page, int size);
}

2. Infrastructure - JPA Entity

@Entity
@Table(name = "users")
@Data
public class UserEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false, unique = true)
    private String email;
    
    private String name;
    private int age;
}

@Repository
public interface UserJpaRepository extends JpaRepository<UserEntity, Long> {
    Optional<UserEntity> findByEmail(String email);
}

3. Adapter реализация

@Repository
@RequiredArgsConstructor
public class UserRepositoryAdapter implements UserRepository {
    
    private final UserJpaRepository jpaRepository;
    private final UserMapper mapper;
    
    @Override
    public Optional<User> findById(Long id) {
        return jpaRepository.findById(id).map(mapper::toDomain);
    }
    
    @Override
    public List<User> findAll() {
        return jpaRepository.findAll().stream()
            .map(mapper::toDomain)
            .collect(Collectors.toList());
    }
    
    @Override
    public Page<User> findAllPaged(int page, int size) {
        return jpaRepository.findAll(PageRequest.of(page, size))
            .map(mapper::toDomain);
    }
}

4. Service Layer

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class UserService {
    
    private final UserRepository userRepository;
    private final UserMapper mapper;
    
    public UserDTO getUserById(Long id) {
        return userRepository.findById(id)
            .map(mapper::toDTO)
            .orElseThrow(() -> new UserNotFoundException("User not found"));
    }
    
    public Page<UserDTO> getUsersPaged(int page, int size) {
        return userRepository.findAllPaged(page, size)
            .map(mapper::toDTO);
    }
}

5. REST Controller

@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {
    
    private final UserService userService;
    
    @GetMapping("/{id}")
    public ResponseEntity<UserDTO> getUserById(@PathVariable Long id) {
        return ResponseEntity.ok(userService.getUserById(id));
    }
    
    @GetMapping
    public ResponseEntity<Page<UserDTO>> getAllUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        return ResponseEntity.ok(userService.getUsersPaged(page, size));
    }
}

6. Exception Handling

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleUserNotFound(
            UserNotFoundException ex) {
        return ResponseEntity
            .status(HttpStatus.NOT_FOUND)
            .body(new ErrorResponse("USER_NOT_FOUND", ex.getMessage()));
    }
}

Best Practices

  • Layered Architecture: Domain → Application → Infrastructure → Presentation
  • No trailing slashes: /api/v1/users не /api/v1/users/
  • Правильные HTTP статусы: 200, 404, 500
  • Пагинация для больших наборов
  • Read-only транзакции для чтения
  • DTO вместо Entity в API
  • Логирование на каждом слое