diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/AddAddressController.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/AddAddressController.java index cae3582..2d0949e 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/AddAddressController.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/AddAddressController.java @@ -4,12 +4,15 @@ import de.strasser.peter.hexagonal.application.port.in.AddAddressUseCase; import de.strasser.peter.hexagonal.application.port.in.commands.AddAddressCommand; import de.strasser.peter.hexagonal.common.Adapter; import de.strasser.peter.hexagonal.web.dto.request.AddAddressRequest; +import de.strasser.peter.hexagonal.web.errors.ErrorHandling; import de.strasser.peter.hexagonal.web.mapper.AddAddressWebMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.math.BigInteger; import java.util.List; @@ -21,6 +24,24 @@ public class AddAddressController { private final AddAddressUseCase addAddressUseCase; private final AddAddressWebMapper addAddressMapper; + @Operation( + summary = "Add Address", + description = "Add an address to a customer by id.", + tags = {"Address"}) + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "successful operation"), + @ApiResponse( + responseCode = "400", + description = "Invalid Parameter", + content = + @Content(schema = @Schema(implementation = ErrorHandling.ErrorResponse.class))), + @ApiResponse( + responseCode = "404", + description = "Customer does not exist", + content = + @Content(schema = @Schema(implementation = ErrorHandling.ErrorResponse.class))) + }) @PostMapping("/v1/customer/address") public void addAddress( @RequestParam BigInteger customerId, @RequestBody AddAddressRequest addAddressRequest) { diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/CustomerCRUDController.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/CustomerCRUDController.java index 791de79..cc78df9 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/CustomerCRUDController.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/CustomerCRUDController.java @@ -4,6 +4,12 @@ import de.strasser.peter.hexagonal.application.port.in.QueryAllCustomersCRUD; import de.strasser.peter.hexagonal.common.Adapter; import de.strasser.peter.hexagonal.web.dto.response.CustomerResponse; import de.strasser.peter.hexagonal.web.mapper.CustomerWebMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -17,6 +23,20 @@ public class CustomerCRUDController { private final QueryAllCustomersCRUD queryAllCustomersCRUD; private final CustomerWebMapper customerMapper; + @Operation( + summary = "Get all customers", + description = "Returns all customers", + tags = {"Customer"}) + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "successful operation", + content = + @Content( + array = + @ArraySchema(schema = @Schema(implementation = CustomerResponse.class)))) + }) @GetMapping("/v1/customers") public List getAllCustomers() { return customerMapper.toResponse(this.queryAllCustomersCRUD.getAll()); diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/RegisterCustomerController.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/RegisterCustomerController.java index c774b62..5c4fcc1 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/RegisterCustomerController.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/RegisterCustomerController.java @@ -3,7 +3,13 @@ package de.strasser.peter.hexagonal.web; import de.strasser.peter.hexagonal.application.port.in.RegisterCustomerUseCase; import de.strasser.peter.hexagonal.common.Adapter; import de.strasser.peter.hexagonal.web.dto.request.RegisterCustomerRequest; +import de.strasser.peter.hexagonal.web.errors.ErrorHandling; import de.strasser.peter.hexagonal.web.mapper.RegisterCustomerWebMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -16,6 +22,15 @@ public class RegisterCustomerController { private final RegisterCustomerUseCase registerCustomerUseCase; private final RegisterCustomerWebMapper registerCustomerMapper; + @Operation( + summary = "Register Customer", + description = "Register a new customer", + tags = {"Customer"}) + @ApiResponses( + value = { + @ApiResponse(responseCode = "200", description = "successful operation"), + @ApiResponse(responseCode = "400", description = "Invalid Parameter") + }) @PostMapping("/v1/register") public void registerCustomer(@RequestBody RegisterCustomerRequest registerCustomerRequest) { registerCustomerUseCase.register(registerCustomerMapper.toCmd(registerCustomerRequest)); diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/config/WebConfig.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/config/WebConfig.java index b42e4ea..94c4c0f 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/config/WebConfig.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/config/WebConfig.java @@ -1,6 +1,25 @@ package de.strasser.peter.hexagonal.web.config; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration -public class WebConfig {} +public class WebConfig { + + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .components(new Components()) + .info( + new Info() + .title("Customer Service API") + .version("v0.0.1") + .description(""" +This service serves as demo project to showcase hexagonal architecture, with some operations on customers with addresses. +""" )); + } +} diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/AddAddressRequest.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/AddAddressRequest.java index 11f0d97..84c69c6 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/AddAddressRequest.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/AddAddressRequest.java @@ -1,5 +1,6 @@ package de.strasser.peter.hexagonal.web.dto.request; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -8,9 +9,22 @@ import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor(force = true) public class AddAddressRequest { + @Schema( + description = "Type of the address", + example = "Electronics", + allowableValues = {"BILLING", "SHIPPING", "DEFAULT"}, + required = true) String type; + + @Schema(description = "street", example = "Parkring 57", required = true) String street; + + @Schema(description = "city", example = "Garching b. München", required = true) String city; + + @Schema(description = "postal code", example = "85748", required = true) Integer zipCode; + + @Schema(description = "country", example = "Germany", required = true) String country; } diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/RegisterCustomerRequest.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/RegisterCustomerRequest.java index fa60053..8a7eff7 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/RegisterCustomerRequest.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/RegisterCustomerRequest.java @@ -1,5 +1,6 @@ package de.strasser.peter.hexagonal.web.dto.request; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -10,7 +11,12 @@ import java.time.LocalDate; @AllArgsConstructor @NoArgsConstructor(force = true) public class RegisterCustomerRequest { + @Schema(description = "name of new customer", example = "Hans", required = true) String name; + + @Schema(description = "birthday of new customer", example = "1980-01-01", required = true) LocalDate birthDay; + + @Schema(description = "password of new customer", example = "S3cretPa$$word!", required = true) String password; } diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/AddressResponse.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/AddressResponse.java index d7fed8d..2105329 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/AddressResponse.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/AddressResponse.java @@ -1,5 +1,6 @@ package de.strasser.peter.hexagonal.web.dto.response; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -8,8 +9,15 @@ import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor public class AddressResponse { - private String street; - private String city; - private Integer zipCode; - private String country; + @Schema(description = "street", example = "Parkring 57", required = true) + String street; + + @Schema(description = "city", example = "Garching b. München", required = true) + String city; + + @Schema(description = "postal code", example = "85748", required = true) + Integer zipCode; + + @Schema(description = "country", example = "Germany", required = true) + String country;; } diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/CustomerResponse.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/CustomerResponse.java index 87de760..dc05206 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/CustomerResponse.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/CustomerResponse.java @@ -1,5 +1,6 @@ package de.strasser.peter.hexagonal.web.dto.response; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -12,9 +13,18 @@ import java.util.Map; @NoArgsConstructor @AllArgsConstructor public class CustomerResponse { + @Schema(description = "id of customer", example = "1", required = true) private BigInteger id; + + @Schema(description = "name of customer", example = "hans", required = true) private String name; + + @Schema(description = "birthday of customer", example = "1980-01-01", required = true) private LocalDate birthday; + + @Schema(description = "addresses of customer", required = true) private Map addresses; + + @Schema(description = "age of customer", example = "41", required = true) private int age; } diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/errors/ErrorHandling.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/errors/ErrorHandling.java index a9cbb46..1e8da4d 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/errors/ErrorHandling.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/errors/ErrorHandling.java @@ -1,6 +1,7 @@ package de.strasser.peter.hexagonal.web.errors; import de.strasser.peter.hexagonal.application.exception.BusinessException; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -28,10 +29,31 @@ public class ErrorHandling { @Value public static class ErrorResponse { + @Schema( + description = "Timestamp in ISO-Format", + example = "2021-05-02T00:31:20.884820", + required = true) String timestamp; + + @Schema(description = "HTTP Status", example = "404", required = true) Integer status; + + @Schema( + description = "Error that was thrown", + example = "CustomerDoesNotExist", + required = true) String error; + + @Schema( + description = "Descriptive error message", + example = "Customer with id '3' does not exist!", + required = true) String message; + + @Schema( + description = "request path that was called", + example = "/v1/customer/address", + required = true) String path; public static ResponseEntity createErrorResp(