Создание REST API на Spring Boot — пошаговое руководство

Краткое введение
Акроним REST означает REpresentational State Transfer, а API — Application Programming Interface. REST API — это сервис, который передаёт запросы и ответы между двумя программными системами, придерживаясь REST-архитектуры.
REST-архитектура создаёт веб-сервисы, доступные по URL, используя основные HTTP-глаголы: POST, GET, PUT и DELETE. Проще говоря, REST API позволяет создавать, читать, обновлять и удалять ресурсы через URL.
В этом руководстве вы научитесь создавать REST API с помощью Spring Boot и MySQL, тестировать его в Postman и покрывать тестами на JUnit.
Инициализация приложения Spring Boot
Сначала создайте базовое Spring Boot приложение. В дополнение к зависимостям для веба потребуется зависимость Spring Data JPA и JDBC-драйвер для выбранной базы данных (в нашем примере — MySQL).
Типичная структура проекта для этого REST API включает три слоя: контроллер, модель и репозиторий.

Важно: используйте современную версию Spring Boot и совместимый драйвер MySQL. Для новых проектов рекомендуется применять Jakarta Persistence (jakarta.persistence) вместо старых javax-пакетов.
Создание модели
Первая сущность — Customer. Она описывает логику данных клиента и сопоставление с таблицей базы данных.
package com.onlineshopaholics.api.model;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Table(name="customer")
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@Column(name="customername")
private String name;
private String email;
public Integer getId() {
return id;
}
public void setId(Integer 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;
}
}Краткое пояснение аннотаций
- @Entity: помечает класс как JPA-сущность. Это говорит JPA, что поля класса используются для создания колонок в реляционной базе.
- @Table: указывает имя таблицы, соответствующей модели.
- @Id: помечает поле уникальным идентификатором сущности.
- @GeneratedValue и GenerationType: определяют стратегию автогенерации значений для идентификатора.
- @Column: связывает поле класса с конкретной колонкой в таблице.
Советы по модели
- Добавьте проверки целостности и аннотации валидации (например, javax.validation.constraints) для полей, таких как email.
- Рассмотрите вариант использования Lombok для сокращения шаблонного кода геттеров/сеттеров в небольших проектам, но учитывайте совместимость с вашей командой.
Создание репозитория
Репозиторий обеспечивает взаимодействие с данными в базе.
package com.onlineshopaholics.api.repository;
import org.springframework.data.repository.CrudRepository;
import com.onlineshopaholics.api.model.Customer;
public interface CustomerRepository extends CrudRepository{} CrudRepository
Создание контроллера
Контроллер реализует REST-эндпоинты, связывая модель и репозиторий.
package com.onlineshopaholics.api.controller;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.onlineshopaholics.api.model.Customer;
import com.onlineshopaholics.api.repository.CustomerRepository;
@RestController
@RequestMapping("/customers")
public class CustomerController {
@Autowired
private CustomerRepository customerRepository;
// create new customer
@PostMapping("/add")
public Customer addNewCustomer(@RequestBody Customer newCustomer){
Customer user = new Customer();
user.setName(newCustomer.getName());
user.setEmail(newCustomer.getEmail());
customerRepository.save(user);
return user;
}
// view all customers
@GetMapping("view/all")
public @ResponseBody Iterable getAllCustomers(){
return customerRepository.findAll();
}
// view specific customer
@GetMapping("view/{id}")
public Optional getCustomer(@PathVariable Integer id) {
return customerRepository.findById(id);
}
// update an existing customer
@PutMapping("/edit/{id}")
public String update( @RequestBody Customer updateCustomer, @PathVariable Integer id) {
return customerRepository.findById(id)
.map(customer -> {
customer.setName(updateCustomer.getName());
customer.setEmail(updateCustomer.getEmail());
customerRepository.save(customer);
return "Customer details have been successfully updated!";
}).orElseGet(() -> {
return "This customer doesn't exist";
});
}
// delete customer
@DeleteMapping("delete/{id}")
public String delete(@PathVariable("id")Integer id) {
customerRepository.deleteById(id);
return "Customer has been successfully deleted!";
}
} Пояснения к аннотациям контроллера
- @RestController: класс обнаруживается Spring и возвращаемые значения методов записываются в тело ответа.
- @RequestMapping: базовый путь для всех методов контроллера.
- @ResponseBody: позволяет возвращать сущности в теле ответа.
- @RequestBody: десериализует тело запроса в объект.
- @RequestParam: извлекает отдельный параметр запроса.
- @PathVariable: сопоставляет часть пути с параметром метода.
- @PostMapping, @GetMapping, @PutMapping, @DeleteMapping: соответствуют CRUD-операциям.
Рекомендации по контроллеру
- Возвращайте корректные HTTP-коды: 201 Created для создания, 204 No Content для успешного удаления без тела, 404 Not Found для отсутствующей сущности.
- Централизуйте обработку ошибок с помощью @ControllerAdvice и ExceptionHandler.
- Добавьте валидацию через @Valid и обработку BindingResult для информативных ответов при ошибках валидации.
Подключение базы данных к приложению
Файл application.properties в папке resources содержит настройки подключения к БД. Для MySQL пример такой:
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=false
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/onlineshopaholics
spring.datasource.username=root
spring.datasource.password=securepw
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver Пояснения
- spring.jpa.hibernate.ddl-auto=update: Hibernate обновляет схему таблицы при старте. Для продакшена предпочтительнее использовать миграции (Flyway или Liquibase).
- ${MYSQL_HOST:localhost}: удобно подставлять хост из окружения, а не хардкодить.
Важно: никогда не храните учётные данные в системах контроля версий. Используйте переменные окружения, секреты в оркестраторе или vault.
Пример docker-compose для локальной разработки
version: '3.8'
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: securepw
MYSQL_DATABASE: onlineshopaholics
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:Преимущества: быстро поднять MySQL локально, использовать тот же JDBC URL с MYSQL_HOST=db.
Создание запросов и тестирование через Postman
Для тестирования REST API удобно использовать Postman или curl. Примеры ключевых шагов описаны ниже.
POST запрос
POST позволяет создавать новых клиентов. В заголовках укажите Content-Type: application/json. В теле укажите JSON, например:
POST http://localhost:8080/customers/add
Content-Type: application/json
{
"name": "Janet Doe",
"email": "janet@example.com"
}

Успешный ответ вернёт созданную сущность с присвоенным id.

GET запрос
Получить всех клиентов:
GET http://localhost:8080/customers/view/all
Получить клиента по id:
GET http://localhost:8080/customers/view/1
PUT запрос
Обновление клиента:
PUT http://localhost:8080/customers/edit/1
Content-Type: application/json
{
"name": "Janet Smith",
"email": "janet.smith@example.com"
}
DELETE запрос
Удаление клиента по id:
DELETE http://localhost:8080/customers/delete/1
Тестирование Spring REST API с помощью JUnit
Spring Boot интегрирован с JUnit и предоставляет тестовые аннотации и утилиты для тестирования контроллеров и репозиториев.
Простой пример интеграционного теста с MockMvc:
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
@AutoConfigureMockMvc
public class CustomerControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void whenPostCustomer_thenCreated() throws Exception {
String json = "{\"name\":\"Test\",\"email\":\"test@example.com\"}";
mockMvc.perform(post("/customers/add")
.contentType(MediaType.APPLICATION_JSON)
.content(json))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").exists());
}
}Советы по тестированию
- Пишите юнит-тесты для сервисного слоя и интеграционные тесты для контроллеров.
- Для базы используйте тестовую конфигурацию с in-memory базой (H2) или Testcontainers для MySQL.
- Покрывайте негативные сценарии: валидация, отсутствующая сущность, дублирование.
Улучшения и альтернативы
- Миграции: вместо ddl-auto используйте Flyway или Liquibase для контроля схемы в продакшене.
- DTO: не возвращайте сущности напрямую — используйте DTO для API-слоя и MapStruct для маппинга.
- Сервисный слой: вынесите бизнес-логику в отдельный сервис между контроллером и репозиторием.
- Безопасность: применяйте Spring Security с JWT или OAuth2 для защиты эндпоинтов.
Безопасность и конфиденциальность
Важно не хранить чувствительные данные (пароли, секреты) в репозитории. Для производства используйте:
- Переменные окружения или менеджер секретов (Vault, AWS Secrets Manager).
- TLS для соединений с клиентами и с базой данных.
- Ограничение привилегий БД: создавайте пользователя с минимальными правами вместо root.
Пример безопасной настройки в application.properties для использования переменных окружения:
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASS}Развертывание и миграция данных
Рекомендации
- Для CI/CD используйте контейнеризацию приложения и инфраструктуры (Docker, Kubernetes).
- Выполняйте миграции схемы в рамках пайплайна с откатом при сбое.
- Тестируйте миграции на staging окружении перед продакшеном.
Контроль ошибок и наблюдаемость
- Логируйте запросы и ошибки с привязкой requestId.
- Экспортируйте метрики (Prometheus) и трассировки (OpenTelemetry).
- Возвращайте клиентам структурированные ошибки с кодами и human-readable сообщениями.
Критерии приёмки
- Все CRUD-эндпоинты доступны и возвращают корректные HTTP-коды.
- Валидация полей с понятными сообщениями об ошибке.
- Покрытие тестами ключевой логики и интеграционных сценариев.
- Конфигурация БД вынесена в переменные окружения.
Чек-листы по ролям
Разработчик
- Реализованы модели, репозиторий и контроллер.
- Добавлены валидация и обработчики ошибок.
- Написаны юнит и интеграционные тесты.
DevOps
- Конфигурация окружений и секретов.
- Настроен CI/CD и миграции.
- Развёрнута БД и мониторинг.
Тестировщик
- Проверены сценарии happy path и негативные кейсы.
- Выполнено тестирование совместимости API и нагрузочное тестирование.
Мини-методология для быстрого запуска
- Создайте Spring Boot проект с зависимостями spring-boot-starter-web, spring-boot-starter-data-jpa и MySQL-драйвер.
- Реализуйте модель, репозиторий, контроллер с базовыми CRUD-операциями.
- Запустите локальную БД через Docker Compose.
- Настройте application.properties через переменные окружения.
- Напишите интеграционные тесты, прогоните их в CI.
- Переведите схему на миграции Flyway и подготовьте контейнер для продакшена.
Модель зрелости API
- Уровень 1: рабочий CRUD API без валидации и тестов.
- Уровень 2: валидация, обработка ошибок, единичные тесты.
- Уровень 3: миграции, CI/CD, безопасность и мониторинг.
Decision flow для выбора подхода к данным
flowchart TD
A[Нужна ли миграция схемы?] -->|Да| B[Использовать Flyway/Liquibase]
A -->|Нет| C[Использовать ddl-auto для разработки]
B --> D[Интеграция в CI/CD]
C --> D
D --> E{Нужен ли тест на реальной БД?}
E -->|Да| F[Использовать Testcontainers]
E -->|Нет| G[H2 для быстрых тестов]Примеры тест-кейсов и критерии приёмки
- Создание клиента возвращает 200 и объект с id.
- Получение несуществующего клиента возвращает 404.
- Обновление корректно меняет поля и возвращает подтверждение.
- Удаление удаляет запись и при повторном запросе возвращает 404.
Сводка
Важно: проектируйте API с учётом безопасности, тестируемости и переносимости. Для production-окружения заменяйте автоматическое обновление схемы миграциями и храните секреты в безопасном хранилище. Тестируйте как успешные, так и негативные сценарии, автоматизируйте CI/CD и мониторинг.
Ключевые шаги: модель, репозиторий, контроллер, конфигурация БД, тестирование и развёртывание.
Полезные ссылки и следующая ступень
- Рассмотрите Flyway или Liquibase для миграций.
- Посмотрите Spring Security для ограничения доступа.
- Используйте Testcontainers для интеграционных тестов с реальной БД.
Важно: адаптируйте рекомендации под требования вашей команды и политики безопасности.