Merge branch 'rest-api' into fixes

This commit is contained in:
Piotr Dec 2024-06-27 01:23:54 +02:00
commit e02ca8c4ae
Signed by: stawros
GPG key ID: F89F27AD8F881A91
8 changed files with 74 additions and 8 deletions

View file

@ -28,6 +28,7 @@
<!-- dependencies --> <!-- dependencies -->
<wiremock.version>3.5.4</wiremock.version> <wiremock.version>3.5.4</wiremock.version>
<openapi.version>2.5.0</openapi.version>
<!-- plugins --> <!-- plugins -->
<jsonschema2pojo.version>1.2.1</jsonschema2pojo.version> <jsonschema2pojo.version>1.2.1</jsonschema2pojo.version>
@ -62,6 +63,11 @@
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${openapi.version}</version>
</dependency>
<!-- Database --> <!-- Database -->
<dependency> <dependency>

View file

@ -79,7 +79,6 @@ Prosty mikroserwis stworzony na potrzeby rekrutacji
"type": "string" "type": "string"
}, },
"currencies": { "currencies": {
"$comment": "TODO: Map -> List",
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/def/currency" "$ref": "#/def/currency"

View file

@ -4,6 +4,7 @@ import eu.ztsh.wymiana.data.entity.CurrencyEntity;
import eu.ztsh.wymiana.data.entity.UserEntity; import eu.ztsh.wymiana.data.entity.UserEntity;
import eu.ztsh.wymiana.model.User; import eu.ztsh.wymiana.model.User;
import eu.ztsh.wymiana.model.UserCreateRequestConfiguredWrapper; import eu.ztsh.wymiana.model.UserCreateRequestConfiguredWrapper;
import eu.ztsh.wymiana.web.model.UserResponse;
import java.util.List; import java.util.List;
@ -19,6 +20,10 @@ public class UserMapper {
CurrencyMapper.pojoMapToEntities(pojo.currencies(), pojo.pesel())); CurrencyMapper.pojoMapToEntities(pojo.currencies(), pojo.pesel()));
} }
public static UserResponse pojoToResponse(User pojo) {
return new UserResponse(pojo.name(), pojo.surname(), pojo.pesel(), pojo.currencies().values().stream().toList());
}
public static UserEntity requestToEntity(UserCreateRequestConfiguredWrapper request) { public static UserEntity requestToEntity(UserCreateRequestConfiguredWrapper request) {
return new UserEntity(request.pesel(), request.name(), request.surname(), return new UserEntity(request.pesel(), request.name(), request.surname(),
List.of(new CurrencyEntity(request.pesel(), request.initialSymbol(), request.initial()))); List.of(new CurrencyEntity(request.pesel(), request.initialSymbol(), request.initial())));

View file

@ -4,9 +4,16 @@ import eu.ztsh.wymiana.exception.InsufficientFundsException;
import eu.ztsh.wymiana.exception.UserNotFoundException; import eu.ztsh.wymiana.exception.UserNotFoundException;
import eu.ztsh.wymiana.service.CurrencyService; import eu.ztsh.wymiana.service.CurrencyService;
import eu.ztsh.wymiana.web.model.CurrencyExchangeRequest; import eu.ztsh.wymiana.web.model.CurrencyExchangeRequest;
import eu.ztsh.wymiana.web.model.UserResponse;
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 jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -22,6 +29,22 @@ public class ExchangeController {
private final CurrencyService currencyService; private final CurrencyService currencyService;
@Operation(summary = "Perform exchange")
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Exchange performed successfully",
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
schema = @Schema(implementation = UserResponse.class))),
@ApiResponse(responseCode = "400",
description = "Insufficient funds",
content = @Content(mediaType = MediaType.TEXT_PLAIN_VALUE)),
@ApiResponse(responseCode = "404",
description = "User not found",
content = @Content(mediaType = MediaType.TEXT_PLAIN_VALUE)),
@ApiResponse(responseCode = "500",
description = "Another error has occurred",
content = @Content(mediaType = MediaType.TEXT_PLAIN_VALUE))
})
@PostMapping @PostMapping
public ResponseEntity<Object> exchange(@Valid @RequestBody CurrencyExchangeRequest request) { public ResponseEntity<Object> exchange(@Valid @RequestBody CurrencyExchangeRequest request) {
try { try {

View file

@ -2,14 +2,21 @@ package eu.ztsh.wymiana.web.controller;
import eu.ztsh.wymiana.exception.UserAlreadyExistsException; import eu.ztsh.wymiana.exception.UserAlreadyExistsException;
import eu.ztsh.wymiana.exception.UserNotFoundException; import eu.ztsh.wymiana.exception.UserNotFoundException;
import eu.ztsh.wymiana.model.User;
import eu.ztsh.wymiana.service.UserService; import eu.ztsh.wymiana.service.UserService;
import eu.ztsh.wymiana.util.UserMapper;
import eu.ztsh.wymiana.validation.ValidationFailedException; import eu.ztsh.wymiana.validation.ValidationFailedException;
import eu.ztsh.wymiana.web.model.UserCreateRequest; import eu.ztsh.wymiana.web.model.UserCreateRequest;
import eu.ztsh.wymiana.web.model.UserResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.ValidationException; import jakarta.validation.ValidationException;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -23,14 +30,23 @@ import org.springframework.web.bind.annotation.RestController;
@Validated @Validated
@RestController @RestController
@RequestMapping(path = "/api/user", produces = "application/json") @RequestMapping(path = "/api/user", produces = "application/json")
@Tag(name="User management", description = "Create or get user")
public class UserController { public class UserController {
private final UserService userService; private final UserService userService;
@Operation(summary = "Get user by PESEL")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "User found"),
@ApiResponse(responseCode = "400", description = "Request not valid", content = @Content),
@ApiResponse(responseCode = "404", description = "User not found", content = @Content),
@ApiResponse(responseCode = "500", description = "Another error has occurred", content = @Content)
})
@GetMapping("{pesel}") @GetMapping("{pesel}")
public ResponseEntity<User> get(@PathVariable("pesel") String pesel) { public ResponseEntity<UserResponse> get(@PathVariable("pesel") String pesel) {
try { try {
return userService.get(pesel) return userService.get(pesel)
.map(UserMapper::pojoToResponse)
.map(ResponseEntity::ok) .map(ResponseEntity::ok)
.orElseThrow(() -> new UserNotFoundException(pesel)); .orElseThrow(() -> new UserNotFoundException(pesel));
} catch (Exception e) { } catch (Exception e) {
@ -42,6 +58,13 @@ public class UserController {
} }
} }
@Operation(summary = "Create user")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "User created", content = @Content),
@ApiResponse(responseCode = "400", description = "Request not valid", content = @Content(mediaType = MediaType.TEXT_PLAIN_VALUE)),
@ApiResponse(responseCode = "409", description = "User already exists", content = @Content(mediaType = MediaType.TEXT_PLAIN_VALUE)),
@ApiResponse(responseCode = "500", description = "Another error has occurred", content = @Content(mediaType = MediaType.TEXT_PLAIN_VALUE))
})
@PostMapping @PostMapping
public ResponseEntity<String> create(@Valid @RequestBody UserCreateRequest request) { public ResponseEntity<String> create(@Valid @RequestBody UserCreateRequest request) {
try { try {

View file

@ -2,6 +2,7 @@ package eu.ztsh.wymiana.web.model;
import eu.ztsh.wymiana.model.Symbol; import eu.ztsh.wymiana.model.Symbol;
import eu.ztsh.wymiana.validation.ValidExchangeRequest; import eu.ztsh.wymiana.validation.ValidExchangeRequest;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.Builder; import lombok.Builder;
import org.hibernate.validator.constraints.pl.PESEL; import org.hibernate.validator.constraints.pl.PESEL;
@ -11,11 +12,11 @@ import java.math.BigDecimal;
@Builder @Builder
@ValidExchangeRequest @ValidExchangeRequest
public record CurrencyExchangeRequest( public record CurrencyExchangeRequest(
@PESEL String pesel, @NotNull @PESEL String pesel,
@NotNull Symbol from, @NotNull Symbol from,
@NotNull Symbol to, @NotNull Symbol to,
BigDecimal toBuy, @Min(0) BigDecimal toBuy,
BigDecimal toSell @Min(0) BigDecimal toSell
) { ) {
} }

View file

@ -12,7 +12,7 @@ import java.math.BigDecimal;
public record UserCreateRequest( public record UserCreateRequest(
@NotNull String name, @NotNull String name,
@NotNull String surname, @NotNull String surname,
@PESEL @Adult String pesel, @PESEL @Adult @NotNull String pesel,
@Min(0) BigDecimal initial) { @NotNull @Min(0) BigDecimal initial) {
} }

View file

@ -0,0 +1,9 @@
package eu.ztsh.wymiana.web.model;
import eu.ztsh.wymiana.model.Currency;
import java.util.List;
public record UserResponse(String name, String surname, String pesel, List<Currency> currencies) {
}