Гид по технологиям

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

6 min read Бэкенд Обновлено 29 Mar 2026
REST API на Spring Boot — руководство
REST API на Spring Boot — руководство

Spring RSET API

Краткое введение

Акроним 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 включает три слоя: контроллер, модель и репозиторий.

REST API file structure

Важно: используйте современную версию 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 уже содержит базовые CRUD-методы (save, findById, findAll, deleteById и др.), поэтому нет необходимости объявлять их вручную.

Создание контроллера

Контроллер реализует 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"
}

REST API post header

REST API post body

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

REST API post response

GET запрос

Получить всех клиентов:

GET http://localhost:8080/customers/view/all

REST API get response

Получить клиента по id:

GET http://localhost:8080/customers/view/1

REST API get by ID response

PUT запрос

Обновление клиента:

PUT http://localhost:8080/customers/edit/1
Content-Type: application/json

{
  "name": "Janet Smith",
  "email": "janet.smith@example.com"
}

REST API put response

DELETE запрос

Удаление клиента по id:

DELETE http://localhost:8080/customers/delete/1

REST API delete response

Тестирование 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 и нагрузочное тестирование.

Мини-методология для быстрого запуска

  1. Создайте Spring Boot проект с зависимостями spring-boot-starter-web, spring-boot-starter-data-jpa и MySQL-драйвер.
  2. Реализуйте модель, репозиторий, контроллер с базовыми CRUD-операциями.
  3. Запустите локальную БД через Docker Compose.
  4. Настройте application.properties через переменные окружения.
  5. Напишите интеграционные тесты, прогоните их в CI.
  6. Переведите схему на миграции 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 для интеграционных тестов с реальной БД.

Важно: адаптируйте рекомендации под требования вашей команды и политики безопасности.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как закрепить вкладки в Safari на Mac
Браузеры

Как закрепить вкладки в Safari на Mac

Shortcuts на Mac — найти, установить, создать
macOS

Shortcuts на Mac — найти, установить, создать

Улучшение качества звука в Windows 11
Windows

Улучшение качества звука в Windows 11

Spotify: частые проблемы и их решения
Технологии

Spotify: частые проблемы и их решения

Как составить бизнес‑план — полное руководство
Бизнес

Как составить бизнес‑план — полное руководство

Включить LTE на Nexus 4 — пошаговый гид
Mobile

Включить LTE на Nexus 4 — пошаговый гид