diff --git a/src/main/java/fr/bonsai/api/adapter/in/web/BonsaiController.java b/src/main/java/fr/bonsai/api/adapter/in/web/BonsaiController.java new file mode 100644 index 0000000..f84731d --- /dev/null +++ b/src/main/java/fr/bonsai/api/adapter/in/web/BonsaiController.java @@ -0,0 +1,43 @@ +package fr.bonsai.api.adapter.in.web; + +import fr.bonsai.api.adapter.in.web.dto.BonsaiRequest; +import fr.bonsai.api.adapter.in.web.dto.BonsaiResponse; +import fr.bonsai.api.application.port.in.CreateBonsaiUseCase; +import fr.bonsai.api.application.port.in.GetBonsaiUseCase; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("/api/bonsais") +public class BonsaiController { + + private final GetBonsaiUseCase getBonsaiUseCase; + private final CreateBonsaiUseCase createBonsaiUseCase; + + public BonsaiController(GetBonsaiUseCase getBonsaiUseCase, CreateBonsaiUseCase createBonsaiUseCase) { + this.getBonsaiUseCase = getBonsaiUseCase; + this.createBonsaiUseCase = createBonsaiUseCase; + } + + @GetMapping + public List getAll() { + return getBonsaiUseCase.getAll().stream() + .map(BonsaiResponse::from) + .toList(); + } + + @GetMapping("/{id}") + public BonsaiResponse getById(@PathVariable UUID id) { + return BonsaiResponse.from(getBonsaiUseCase.getById(id)); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public BonsaiResponse create(@RequestBody BonsaiRequest request) { + var command = new CreateBonsaiUseCase.Command(request.name(), request.species(), request.ageYears()); + return BonsaiResponse.from(createBonsaiUseCase.create(command)); + } +} diff --git a/src/main/java/fr/bonsai/api/adapter/in/web/dto/BonsaiRequest.java b/src/main/java/fr/bonsai/api/adapter/in/web/dto/BonsaiRequest.java new file mode 100644 index 0000000..cecec45 --- /dev/null +++ b/src/main/java/fr/bonsai/api/adapter/in/web/dto/BonsaiRequest.java @@ -0,0 +1,3 @@ +package fr.bonsai.api.adapter.in.web.dto; + +public record BonsaiRequest(String name, String species, int ageYears) {} diff --git a/src/main/java/fr/bonsai/api/adapter/in/web/dto/BonsaiResponse.java b/src/main/java/fr/bonsai/api/adapter/in/web/dto/BonsaiResponse.java new file mode 100644 index 0000000..83b7977 --- /dev/null +++ b/src/main/java/fr/bonsai/api/adapter/in/web/dto/BonsaiResponse.java @@ -0,0 +1,12 @@ +package fr.bonsai.api.adapter.in.web.dto; + +import fr.bonsai.api.domain.model.Bonsai; + +import java.util.UUID; + +public record BonsaiResponse(UUID id, String name, String species, int ageYears) { + + public static BonsaiResponse from(Bonsai bonsai) { + return new BonsaiResponse(bonsai.getId(), bonsai.getName(), bonsai.getSpecies(), bonsai.getAgeYears()); + } +} diff --git a/src/main/java/fr/bonsai/api/adapter/out/persistence/InMemoryBonsaiRepository.java b/src/main/java/fr/bonsai/api/adapter/out/persistence/InMemoryBonsaiRepository.java new file mode 100644 index 0000000..bae9820 --- /dev/null +++ b/src/main/java/fr/bonsai/api/adapter/out/persistence/InMemoryBonsaiRepository.java @@ -0,0 +1,28 @@ +package fr.bonsai.api.adapter.out.persistence; + +import fr.bonsai.api.application.port.out.BonsaiRepository; +import fr.bonsai.api.domain.model.Bonsai; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class InMemoryBonsaiRepository implements BonsaiRepository { + + private final Map store = new ConcurrentHashMap<>(); + + @Override + public List findAll() { + return List.copyOf(store.values()); + } + + @Override + public Optional findById(UUID id) { + return Optional.ofNullable(store.get(id)); + } + + @Override + public Bonsai save(Bonsai bonsai) { + store.put(bonsai.getId(), bonsai); + return bonsai; + } +} diff --git a/src/main/java/fr/bonsai/api/application/port/in/CreateBonsaiUseCase.java b/src/main/java/fr/bonsai/api/application/port/in/CreateBonsaiUseCase.java new file mode 100644 index 0000000..a804940 --- /dev/null +++ b/src/main/java/fr/bonsai/api/application/port/in/CreateBonsaiUseCase.java @@ -0,0 +1,10 @@ +package fr.bonsai.api.application.port.in; + +import fr.bonsai.api.domain.model.Bonsai; + +public interface CreateBonsaiUseCase { + + record Command(String name, String species, int ageYears) {} + + Bonsai create(Command command); +} diff --git a/src/main/java/fr/bonsai/api/application/port/in/GetBonsaiUseCase.java b/src/main/java/fr/bonsai/api/application/port/in/GetBonsaiUseCase.java new file mode 100644 index 0000000..63bbad6 --- /dev/null +++ b/src/main/java/fr/bonsai/api/application/port/in/GetBonsaiUseCase.java @@ -0,0 +1,13 @@ +package fr.bonsai.api.application.port.in; + +import fr.bonsai.api.domain.model.Bonsai; + +import java.util.List; +import java.util.UUID; + +public interface GetBonsaiUseCase { + + List getAll(); + + Bonsai getById(UUID id); +} diff --git a/src/main/java/fr/bonsai/api/application/port/out/BonsaiRepository.java b/src/main/java/fr/bonsai/api/application/port/out/BonsaiRepository.java new file mode 100644 index 0000000..3817ead --- /dev/null +++ b/src/main/java/fr/bonsai/api/application/port/out/BonsaiRepository.java @@ -0,0 +1,16 @@ +package fr.bonsai.api.application.port.out; + +import fr.bonsai.api.domain.model.Bonsai; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public interface BonsaiRepository { + + List findAll(); + + Optional findById(UUID id); + + Bonsai save(Bonsai bonsai); +} diff --git a/src/main/java/fr/bonsai/api/application/usecase/BonsaiService.java b/src/main/java/fr/bonsai/api/application/usecase/BonsaiService.java new file mode 100644 index 0000000..55a5fbe --- /dev/null +++ b/src/main/java/fr/bonsai/api/application/usecase/BonsaiService.java @@ -0,0 +1,36 @@ +package fr.bonsai.api.application.usecase; + +import fr.bonsai.api.application.port.in.CreateBonsaiUseCase; +import fr.bonsai.api.application.port.in.GetBonsaiUseCase; +import fr.bonsai.api.application.port.out.BonsaiRepository; +import fr.bonsai.api.domain.model.Bonsai; + +import java.util.List; +import java.util.NoSuchElementException; +import java.util.UUID; + +public class BonsaiService implements GetBonsaiUseCase, CreateBonsaiUseCase { + + private final BonsaiRepository repository; + + public BonsaiService(BonsaiRepository repository) { + this.repository = repository; + } + + @Override + public List getAll() { + return repository.findAll(); + } + + @Override + public Bonsai getById(UUID id) { + return repository.findById(id) + .orElseThrow(() -> new NoSuchElementException("Bonsai not found: " + id)); + } + + @Override + public Bonsai create(Command command) { + Bonsai bonsai = Bonsai.create(command.name(), command.species(), command.ageYears()); + return repository.save(bonsai); + } +} diff --git a/src/main/java/fr/bonsai/api/config/BeanConfig.java b/src/main/java/fr/bonsai/api/config/BeanConfig.java new file mode 100644 index 0000000..14adc38 --- /dev/null +++ b/src/main/java/fr/bonsai/api/config/BeanConfig.java @@ -0,0 +1,21 @@ +package fr.bonsai.api.config; + +import fr.bonsai.api.adapter.out.persistence.InMemoryBonsaiRepository; +import fr.bonsai.api.application.port.out.BonsaiRepository; +import fr.bonsai.api.application.usecase.BonsaiService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class BeanConfig { + + @Bean + public BonsaiRepository bonsaiRepository() { + return new InMemoryBonsaiRepository(); + } + + @Bean + public BonsaiService bonsaiService(BonsaiRepository repository) { + return new BonsaiService(repository); + } +} diff --git a/src/main/java/fr/bonsai/api/domain/model/Bonsai.java b/src/main/java/fr/bonsai/api/domain/model/Bonsai.java new file mode 100644 index 0000000..37ef7f4 --- /dev/null +++ b/src/main/java/fr/bonsai/api/domain/model/Bonsai.java @@ -0,0 +1,27 @@ +package fr.bonsai.api.domain.model; + +import java.util.UUID; + +public class Bonsai { + + private final UUID id; + private String name; + private String species; + private int ageYears; + + public Bonsai(UUID id, String name, String species, int ageYears) { + this.id = id; + this.name = name; + this.species = species; + this.ageYears = ageYears; + } + + public static Bonsai create(String name, String species, int ageYears) { + return new Bonsai(UUID.randomUUID(), name, species, ageYears); + } + + public UUID getId() { return id; } + public String getName() { return name; } + public String getSpecies() { return species; } + public int getAgeYears() { return ageYears; } +}