diff --git a/pom.xml b/pom.xml
index 0c754f19..2d6d7aa8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,12 +26,36 @@
spring-boot-starter
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ 2.3.0
+
+
+
+ com.h2database
+ h2
+ runtime
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
org.springframework.boot
spring-boot-starter-test
test
+
+ org.projectlombok
+ lombok
+ 1.18.28
+ provided
+
+
org.springframework.boot
spring-boot-starter-data-jpa
diff --git a/src/main/java/mate/academy/rickandmorty/config/AppConfig.java b/src/main/java/mate/academy/rickandmorty/config/AppConfig.java
new file mode 100644
index 00000000..29541476
--- /dev/null
+++ b/src/main/java/mate/academy/rickandmorty/config/AppConfig.java
@@ -0,0 +1,29 @@
+package mate.academy.rickandmorty.config;
+
+import java.util.Random;
+import mate.academy.rickandmorty.service.CharacterService;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+@Configuration
+public class AppConfig {
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
+ @Bean
+ public Random random() {
+ return new Random();
+ }
+
+ @Bean
+ public CommandLineRunner commandLineRunner(CharacterService characterService) {
+ return args -> {
+ characterService.fetchCharacters();
+ };
+ }
+}
diff --git a/src/main/java/mate/academy/rickandmorty/controller/CharacterController.java b/src/main/java/mate/academy/rickandmorty/controller/CharacterController.java
new file mode 100644
index 00000000..2e74b230
--- /dev/null
+++ b/src/main/java/mate/academy/rickandmorty/controller/CharacterController.java
@@ -0,0 +1,34 @@
+package mate.academy.rickandmorty.controller;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import mate.academy.rickandmorty.dto.CharacterResponseDto;
+import mate.academy.rickandmorty.service.CharacterService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(value = "/api/characters")
+@Tag(name = "Character API", description = "Operations related to characters from Rick and Morty")
+public class CharacterController {
+ private final CharacterService characterService;
+
+ @GetMapping("/random")
+ @Operation(summary = "Get a random character",
+ description = "Returns a random character from the database.")
+ public CharacterResponseDto getRandomCharacter() {
+ return characterService.getRandomCharacter();
+ }
+
+ @GetMapping
+ @Operation(summary = "Search characters by name",
+ description = "Returns a list of characters whose name contains the specified word.")
+ public List searchCharactersByName(@RequestParam String word) {
+ return characterService.searchCharactersByName(word);
+ }
+}
diff --git a/src/main/java/mate/academy/rickandmorty/dto/CharacterListDto.java b/src/main/java/mate/academy/rickandmorty/dto/CharacterListDto.java
new file mode 100644
index 00000000..13d317b5
--- /dev/null
+++ b/src/main/java/mate/academy/rickandmorty/dto/CharacterListDto.java
@@ -0,0 +1,14 @@
+package mate.academy.rickandmorty.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+import mate.academy.rickandmorty.model.CharacterApiResponse;
+
+@Getter
+@Setter
+public class CharacterListDto {
+ @JsonProperty("results")
+ private List results;
+}
diff --git a/src/main/java/mate/academy/rickandmorty/dto/CharacterResponseDto.java b/src/main/java/mate/academy/rickandmorty/dto/CharacterResponseDto.java
new file mode 100644
index 00000000..29aab06c
--- /dev/null
+++ b/src/main/java/mate/academy/rickandmorty/dto/CharacterResponseDto.java
@@ -0,0 +1,10 @@
+package mate.academy.rickandmorty.dto;
+
+public record CharacterResponseDto(
+ Long id,
+ int externalId,
+ String name,
+ String status,
+ String gender
+) {
+}
diff --git a/src/main/java/mate/academy/rickandmorty/model/Character.java b/src/main/java/mate/academy/rickandmorty/model/Character.java
new file mode 100644
index 00000000..698c6d13
--- /dev/null
+++ b/src/main/java/mate/academy/rickandmorty/model/Character.java
@@ -0,0 +1,25 @@
+package mate.academy.rickandmorty.model;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@Entity
+@Table(name = "characters")
+public class Character {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+ private int externalId;
+ @NotNull
+ private String name;
+ private String status;
+ private String gender;
+}
diff --git a/src/main/java/mate/academy/rickandmorty/model/CharacterApiResponse.java b/src/main/java/mate/academy/rickandmorty/model/CharacterApiResponse.java
new file mode 100644
index 00000000..a8c0740b
--- /dev/null
+++ b/src/main/java/mate/academy/rickandmorty/model/CharacterApiResponse.java
@@ -0,0 +1,18 @@
+package mate.academy.rickandmorty.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CharacterApiResponse {
+ @JsonProperty("id")
+ private int id;
+ @JsonProperty("name")
+ private String name;
+ @JsonProperty("status")
+ private String status;
+ @JsonProperty("gender")
+ private String gender;
+}
diff --git a/src/main/java/mate/academy/rickandmorty/repository/CharacterRepository.java b/src/main/java/mate/academy/rickandmorty/repository/CharacterRepository.java
new file mode 100644
index 00000000..fd513c6d
--- /dev/null
+++ b/src/main/java/mate/academy/rickandmorty/repository/CharacterRepository.java
@@ -0,0 +1,9 @@
+package mate.academy.rickandmorty.repository;
+
+import mate.academy.rickandmorty.model.Character;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface CharacterRepository extends JpaRepository {
+}
diff --git a/src/main/java/mate/academy/rickandmorty/service/CharacterService.java b/src/main/java/mate/academy/rickandmorty/service/CharacterService.java
new file mode 100644
index 00000000..c26b9ebc
--- /dev/null
+++ b/src/main/java/mate/academy/rickandmorty/service/CharacterService.java
@@ -0,0 +1,14 @@
+package mate.academy.rickandmorty.service;
+
+import java.util.List;
+import mate.academy.rickandmorty.dto.CharacterResponseDto;
+import org.springframework.stereotype.Service;
+
+@Service
+public interface CharacterService {
+ void fetchCharacters();
+
+ CharacterResponseDto getRandomCharacter();
+
+ List searchCharactersByName(String word);
+}
diff --git a/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java
new file mode 100644
index 00000000..50fb28d0
--- /dev/null
+++ b/src/main/java/mate/academy/rickandmorty/service/impl/CharacterServiceImpl.java
@@ -0,0 +1,96 @@
+package mate.academy.rickandmorty.service.impl;
+
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import mate.academy.rickandmorty.dto.CharacterListDto;
+import mate.academy.rickandmorty.dto.CharacterResponseDto;
+import mate.academy.rickandmorty.model.Character;
+import mate.academy.rickandmorty.repository.CharacterRepository;
+import mate.academy.rickandmorty.service.CharacterService;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.RestTemplate;
+
+@Service
+@RequiredArgsConstructor
+public class CharacterServiceImpl implements CharacterService {
+ private final RestTemplate restTemplate;
+ private final CharacterRepository characterRepository;
+ private final Random random;
+
+ @Override
+ public void fetchCharacters() {
+ String url = "https://rickandmortyapi.com/api/character";
+ int page = 1;
+
+ while (true) {
+ String pageUrl = url + "?page=" + page;
+ CharacterListDto response;
+
+ try {
+ response = restTemplate.getForObject(pageUrl, CharacterListDto.class);
+ } catch (HttpClientErrorException e) {
+ if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
+ break;
+ }
+ throw e;
+ }
+
+ if (response == null || response.getResults() == null
+ || response.getResults().isEmpty()) {
+ break;
+ }
+
+ List characters = response.getResults()
+ .stream()
+ .map(result -> {
+ Character character = new Character();
+ character.setExternalId(result.getId());
+
+ if (result.getName() != null) {
+ character.setName(result.getName());
+ } else {
+ throw new IllegalArgumentException("Field name is missing");
+ }
+
+ character.setGender(result.getGender());
+ character.setStatus(result.getStatus());
+ return character;
+ }).collect(Collectors.toList());
+
+ characterRepository.saveAll(characters);
+
+ page++;
+ }
+ }
+
+ @Override
+ public CharacterResponseDto getRandomCharacter() {
+ int randomId = random.nextInt(1, (int) characterRepository.count());
+ Character character = characterRepository
+ .findById(Long.valueOf(randomId))
+ .orElseThrow(() -> new RuntimeException("Character not found"));
+ return toDto(character);
+ }
+
+ @Override
+ public List searchCharactersByName(String word) {
+ return characterRepository.findAll().stream()
+ .filter(ch -> ch.getName().toLowerCase().contains(word.toLowerCase()))
+ .map(this::toDto)
+ .collect(Collectors.toList());
+ }
+
+ public CharacterResponseDto toDto(Character character) {
+ return new CharacterResponseDto(
+ character.getId(),
+ character.getExternalId(),
+ character.getName(),
+ character.getStatus(),
+ character.getGender()
+ );
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 8b137891..986c9ed9 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1 +1,7 @@
+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
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
index bc2fdde8..6239a984 100644
--- a/src/test/resources/application.properties
+++ b/src/test/resources/application.properties
@@ -3,3 +3,4 @@ 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