diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b8d7560..bd84094a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
-### Conforming to API v3
+### Added
+
+- [Springdoc](https://springdoc.org) library, to enrich the project with two new features:
+ - Generation of an OpenAPI 3.0 spec file, akin to [the Trebol API](https://github.com/trebol-ecommerce/api)'s
+ - Generation of a [Swagger UI](https://swagger.io/tools/swagger-ui/) page and endpoint.
+
+### Changed
+
+#### Conforming to API v3
- Follow new specification for error messages
- Introduce new model class `AppError`
@@ -68,6 +76,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- All PUT,PATCH,DELETE,OPTIONS requests return 204
- Remove duplicated functionality endpoint `/public/checkout/result/{token}`
- Served the same purpose as `/public/receipt/{token}`
+ - Remove support for paths with leading slash
+ - For example, `/public/checkout/` is no longer accepted, only `/public/checkout`
## [v0.2.4] - 2024-08-28
diff --git a/pom.xml b/pom.xml
index bd557b5c..8d703bce 100644
--- a/pom.xml
+++ b/pom.xml
@@ -157,6 +157,11 @@
unirest-java
${unirest.version}
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ 2.6.0
+
diff --git a/src/main/java/org/trebol/api/controllers/AccessController.java b/src/main/java/org/trebol/api/controllers/AccessController.java
index f13f54e8..c3cd2096 100644
--- a/src/main/java/org/trebol/api/controllers/AccessController.java
+++ b/src/main/java/org/trebol/api/controllers/AccessController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import io.jsonwebtoken.Claims;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -46,6 +48,7 @@
@RestController
@RequestMapping("/access")
+@Tag(name = "User Accounts")
@PreAuthorize("isAuthenticated()")
public class AccessController {
private final AuthorizationHeaderParserService jwtClaimsParserService;
@@ -66,7 +69,8 @@ public AccessController(
this.regexMatcherService = regexMatcherService;
}
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List authorized API routes")
public AuthorizedAccessPojo getApiRoutesAccess(@RequestHeader HttpHeaders requestHeaders)
throws UsernameNotFoundException, IllegalStateException {
UserDetails userDetails = this.getUserDetails(requestHeaders);
@@ -79,7 +83,8 @@ public AuthorizedAccessPojo getApiRoutesAccess(@RequestHeader HttpHeaders reques
.build();
}
- @GetMapping({"/{apiRoute}", "/{apiRoute}/"})
+ @GetMapping("/{apiRoute}")
+ @Operation(summary = "List authorized access to API route")
public AuthorizedAccessPojo getApiResourceAccess(
@RequestHeader HttpHeaders requestHeaders,
@PathVariable String apiRoute)
diff --git a/src/main/java/org/trebol/api/controllers/AccountProfileController.java b/src/main/java/org/trebol/api/controllers/AccountProfileController.java
index fe83bcf0..acd0a8af 100644
--- a/src/main/java/org/trebol/api/controllers/AccountProfileController.java
+++ b/src/main/java/org/trebol/api/controllers/AccountProfileController.java
@@ -20,6 +20,8 @@
package org.trebol.api.controllers;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
@@ -36,6 +38,7 @@
@RestController
@RequestMapping("/account/profile")
+@Tag(name = "User Accounts")
@PreAuthorize("isAuthenticated()")
public class AccountProfileController {
private final ProfileService userProfileService;
@@ -47,14 +50,16 @@ public AccountProfileController(
this.userProfileService = userProfileService;
}
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "View stored profile information")
public PersonPojo getProfile(Principal principal)
throws EntityNotFoundException {
String username = principal.getName();
return userProfileService.getProfileFromUserName(username);
}
- @PutMapping({"", "/"})
+ @PutMapping
+ @Operation(summary = "Replace stored profile information")
public void updateProfile(Principal principal, @RequestBody PersonPojo newProfile)
throws EntityNotFoundException, BadInputException {
String username = principal.getName();
diff --git a/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java b/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java
index 5ca68511..b826c3c8 100644
--- a/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataBillingTypesController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -40,6 +42,7 @@
@RestController
@RequestMapping("/data/billing_types")
+@Tag(name = "Params management")
public class DataBillingTypesController
extends DataGenericController {
@@ -54,7 +57,8 @@ public DataBillingTypesController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List billing types.")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
return super.readMany(allRequestParams);
}
diff --git a/src/main/java/org/trebol/api/controllers/DataCustomersController.java b/src/main/java/org/trebol/api/controllers/DataCustomersController.java
index 7a0ce1b6..0b3a7019 100644
--- a/src/main/java/org/trebol/api/controllers/DataCustomersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataCustomersController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
@@ -45,6 +47,7 @@
@RestController
@RequestMapping("/data/customers")
+@Tag(name = "People management")
@PreAuthorize("isAuthenticated()")
public class DataCustomersController
extends DataCrudGenericController {
@@ -60,14 +63,16 @@ public DataCustomersController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List customers.")
@PreAuthorize("hasAuthority('customers:read')")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
return super.readMany(allRequestParams);
}
@Override
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Register new customer.")
@PreAuthorize("hasAuthority('customers:create')")
@ResponseStatus(CREATED)
public void create(@Valid @RequestBody PersonPojo input)
@@ -76,7 +81,8 @@ public void create(@Valid @RequestBody PersonPojo input)
}
@Override
- @PutMapping({"", "/"})
+ @PutMapping
+ @Operation(summary = "Replace customers data.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('customers:update')")
public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map requestParams)
@@ -85,7 +91,8 @@ public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataImagesController.java b/src/main/java/org/trebol/api/controllers/DataImagesController.java
index b55ad28a..a0a22fb2 100644
--- a/src/main/java/org/trebol/api/controllers/DataImagesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataImagesController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
@RestController
@RequestMapping("/data/images")
+@Tag(name = "Images management")
@PreAuthorize("isAuthenticated()")
public class DataImagesController
extends DataCrudGenericController {
@@ -69,14 +72,16 @@ public DataImagesController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List image links data.")
@PreAuthorize("hasAuthority('images:read')")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
return super.readMany(allRequestParams);
}
@Override
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Define new image links.")
@ResponseStatus(CREATED)
@PreAuthorize("hasAuthority('images:create')")
public void create(@Valid @RequestBody ImagePojo input)
@@ -85,7 +90,8 @@ public void create(@Valid @RequestBody ImagePojo input)
}
@Override
- @PutMapping({"", "/"})
+ @PutMapping
+ @Operation(summary = "Replace image links data.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('images:update')")
public void update(@Valid @RequestBody ImagePojo input, @RequestParam Map requestParams)
@@ -94,7 +100,8 @@ public void update(@Valid @RequestBody ImagePojo input, @RequestParam Map requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java b/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java
index 81f835d0..e2dee329 100644
--- a/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataOrderStatusesController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
@@ -41,6 +43,7 @@
@RestController
@RequestMapping("/data/order_statuses")
+@Tag(name = "Params management")
@PreAuthorize("isAuthenticated()")
public class DataOrderStatusesController
extends DataGenericController {
@@ -56,7 +59,8 @@ public DataOrderStatusesController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List order statuses.")
@PreAuthorize("hasAuthority('order_statuses:read')")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
return super.readMany(allRequestParams);
diff --git a/src/main/java/org/trebol/api/controllers/DataOrdersController.java b/src/main/java/org/trebol/api/controllers/DataOrdersController.java
index e1daf6e8..c2447624 100644
--- a/src/main/java/org/trebol/api/controllers/DataOrdersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataOrdersController.java
@@ -22,6 +22,8 @@
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -61,6 +63,7 @@
@RestController
@RequestMapping("/data/orders")
+@Tag(name = "Orders management")
@PreAuthorize("isAuthenticated()")
public class DataOrdersController
extends DataCrudGenericController {
@@ -83,7 +86,8 @@ public DataOrdersController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List orders.")
@PreAuthorize("hasAuthority('orders:read')")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
if (allRequestParams!=null) {
@@ -106,7 +110,8 @@ public DataPagePojo readMany(@RequestParam Map allReq
}
@Override
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Create new orders.")
@ResponseStatus(CREATED)
@PreAuthorize("hasAuthority('orders:create')")
public void create(@Valid @RequestBody OrderPojo input)
@@ -115,7 +120,8 @@ public void create(@Valid @RequestBody OrderPojo input)
}
@Override
- @PutMapping({"", "/"})
+ @PutMapping
+ @Operation(summary = "Replace orders data.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('orders:update')")
public void update(@Valid @RequestBody OrderPojo input, @RequestParam Map requestParams)
@@ -124,7 +130,8 @@ public void update(@Valid @RequestBody OrderPojo input, @RequestParam Map requestParams)
@@ -143,7 +151,8 @@ public void delete(@RequestParam Map requestParams)
super.delete(requestParams);
}
- @PostMapping({"/confirmation", "/confirmation/"})
+ @PostMapping("/confirmation")
+ @Operation(summary = "Confirm a pending order.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('orders:update')")
public void confirmSell(@RequestBody OrderPojo sell)
@@ -155,7 +164,8 @@ public void confirmSell(@RequestBody OrderPojo sell)
}
}
- @PostMapping({"/rejection", "/rejection/"})
+ @PostMapping("/rejection")
+ @Operation(summary = "Reject a pending order.")
@PreAuthorize("hasAuthority('orders:update')")
public void rejectSell(@RequestBody OrderPojo sell)
throws BadInputException, MailingServiceException {
@@ -165,7 +175,8 @@ public void rejectSell(@RequestBody OrderPojo sell)
}
}
- @PostMapping({"/completion", "/completion/"})
+ @PostMapping("/completion")
+ @Operation(summary = "Mark an order as completed.")
@PreAuthorize("hasAuthority('orders:update')")
public void completeSell(@RequestBody OrderPojo sell)
throws BadInputException, MailingServiceException {
diff --git a/src/main/java/org/trebol/api/controllers/DataPeopleController.java b/src/main/java/org/trebol/api/controllers/DataPeopleController.java
index f2cfb03c..c7f99254 100644
--- a/src/main/java/org/trebol/api/controllers/DataPeopleController.java
+++ b/src/main/java/org/trebol/api/controllers/DataPeopleController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
@@ -41,6 +43,7 @@
@RestController
@RequestMapping("/data/people")
+@Tag(name = "People management")
@PreAuthorize("isAuthenticated()")
public class DataPeopleController
extends DataGenericController {
@@ -56,7 +59,8 @@ public DataPeopleController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List people.")
@PreAuthorize("hasAuthority('people:read')")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
return super.readMany(allRequestParams);
diff --git a/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java b/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java
index c3fc359e..512008e6 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductCategoriesController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
@RestController
@RequestMapping("/data/product_categories")
+@Tag(name = "Product Categories management")
public class DataProductCategoriesController
extends DataCrudGenericController {
@@ -68,7 +71,8 @@ public DataProductCategoriesController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List product categories.")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
if (allRequestParams==null || allRequestParams.isEmpty()) {
allRequestParams = Map.of("parentId", "");
@@ -77,7 +81,8 @@ public DataPagePojo readMany(@RequestParam Map requestParams)
@@ -95,7 +101,8 @@ public void update(@Valid @RequestBody ProductCategoryPojo input, @RequestParam
}
@Override
- @PatchMapping({"", "/"})
+ @PatchMapping
+ @Operation(summary = "Update parts of product categories data.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('product_categories:update')")
public void partialUpdate(
@@ -106,7 +113,8 @@ public void partialUpdate(
}
@Override
- @DeleteMapping({"", "/"})
+ @DeleteMapping
+ @Operation(summary = "Remove product categories.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('product_categories:delete')")
public void delete(@RequestParam Map requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java b/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java
index f2e6dba9..d71cebbf 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductListContentsController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.Predicate;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
@@ -68,6 +70,7 @@
@RestController
@RequestMapping("/data/product_list_contents")
+@Tag(name = "Product Lists management")
public class DataProductListContentsController {
private static final String ITEM_NOT_FOUND = "Requested item(s) not found";
private final PaginationService paginationService;
@@ -97,7 +100,8 @@ public DataProductListContentsController(
this.itemConverterService = itemConverterService;
}
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "View contents of product lists.")
public DataPagePojo readContents(@RequestParam Map requestParams)
throws BadInputException, EntityNotFoundException {
Optional match = this.fetchProductListByCode(requestParams);
@@ -128,7 +132,8 @@ public DataPagePojo readContents(@RequestParam Map
return new DataPagePojo<>(products, pageIndex, totalCount, pageSize);
}
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Add products to lists.")
@ResponseStatus(CREATED)
@PreAuthorize("hasAuthority('product_lists:contents')")
public void addToContents(@Valid @RequestBody ProductPojo input,
@@ -151,7 +156,8 @@ public void addToContents(@Valid @RequestBody ProductPojo input,
}
}
- @PutMapping({"", "/"})
+ @PutMapping
+ @Operation(summary = "Fully replace contents of product lists.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('product_lists:contents')")
public void updateContents(@RequestBody Collection input,
@@ -177,7 +183,8 @@ public void updateContents(@RequestBody Collection input,
}
}
- @DeleteMapping({"", "/"})
+ @DeleteMapping
+ @Operation(summary = "Remove products from lists.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('product_lists:contents')")
public void deleteFromContents(@RequestParam Map requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataProductListsController.java b/src/main/java/org/trebol/api/controllers/DataProductListsController.java
index 2c63068b..74993d84 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductListsController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductListsController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
@RestController
@RequestMapping("/data/product_lists")
+@Tag(name = "Product Lists management")
public class DataProductListsController
extends DataCrudGenericController {
@@ -68,13 +71,15 @@ public DataProductListsController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "View product lists.")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
return super.readMany(allRequestParams);
}
@Override
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Define new product lists.")
@ResponseStatus(CREATED)
@PreAuthorize("hasAuthority('product_lists:create')")
public void create(@Valid @RequestBody ProductListPojo input)
@@ -83,7 +88,8 @@ public void create(@Valid @RequestBody ProductListPojo input)
}
@Override
- @PutMapping({"", "/"})
+ @PutMapping
+ @Operation(summary = "Replace product lists data.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('product_lists:update')")
public void update(@Valid @RequestBody ProductListPojo input, @RequestParam Map requestParams)
@@ -92,7 +98,8 @@ public void update(@Valid @RequestBody ProductListPojo input, @RequestParam Map<
}
@Override
- @PatchMapping({"", "/"})
+ @PatchMapping
+ @Operation(summary = "Update parts of product lists data.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('product_lists:update')")
public void partialUpdate(
@@ -103,7 +110,8 @@ public void partialUpdate(
}
@Override
- @DeleteMapping({"", "/"})
+ @DeleteMapping
+ @Operation(summary = "Remove product lists.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('product_lists:delete')")
public void delete(@RequestParam Map requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataProductsController.java b/src/main/java/org/trebol/api/controllers/DataProductsController.java
index b4837c0a..35bdeb41 100644
--- a/src/main/java/org/trebol/api/controllers/DataProductsController.java
+++ b/src/main/java/org/trebol/api/controllers/DataProductsController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
@RestController
@RequestMapping("/data/products")
+@Tag(name = "Products management")
public class DataProductsController
extends DataCrudGenericController {
@@ -68,13 +71,15 @@ public DataProductsController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List products.")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
return super.readMany(allRequestParams);
}
@Override
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Define new products.")
@ResponseStatus(CREATED)
@PreAuthorize("hasAuthority('products:create')")
public void create(@Valid @RequestBody ProductPojo input)
@@ -83,7 +88,8 @@ public void create(@Valid @RequestBody ProductPojo input)
}
@Override
- @PutMapping({"", "/"})
+ @PutMapping
+ @Operation(summary = "Replace products data.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('products:update')")
public void update(@Valid @RequestBody ProductPojo input, @RequestParam Map requestParams)
@@ -92,7 +98,8 @@ public void update(@Valid @RequestBody ProductPojo input, @RequestParam Map requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java b/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java
index 38b99e9b..c4c466a5 100644
--- a/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java
+++ b/src/main/java/org/trebol/api/controllers/DataSalespeopleController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -53,6 +55,7 @@
@RestController
@RequestMapping("/data/salespeople")
+@Tag(name = "People management")
@PreAuthorize("isAuthenticated()")
public class DataSalespeopleController
extends DataCrudGenericController {
@@ -68,14 +71,16 @@ public DataSalespeopleController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List salespeople.")
@PreAuthorize("hasAuthority('salespeople:read')")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
return super.readMany(allRequestParams);
}
@Override
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Register new salespeople.")
@ResponseStatus(CREATED)
@PreAuthorize("hasAuthority('salespeople:create')")
public void create(@Valid @RequestBody PersonPojo input)
@@ -84,7 +89,8 @@ public void create(@Valid @RequestBody PersonPojo input)
}
@Override
- @PutMapping({"", "/"})
+ @PutMapping
+ @Operation(summary = "Replace salespeople data.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('salespeople:update')")
public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map requestParams)
@@ -93,7 +99,8 @@ public void update(@Valid @RequestBody PersonPojo input, @RequestParam Map requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataShippersController.java b/src/main/java/org/trebol/api/controllers/DataShippersController.java
index 07a4ad49..6a44e3f0 100644
--- a/src/main/java/org/trebol/api/controllers/DataShippersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataShippersController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
@RestController
@RequestMapping("/data/shippers")
+@Tag(name = "Shippers management")
public class DataShippersController
extends DataCrudGenericController {
@@ -68,13 +71,15 @@ public DataShippersController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List shippers.")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
return super.readMany(allRequestParams);
}
@Override
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Define new shippers.")
@ResponseStatus(CREATED)
@PreAuthorize("hasAuthority('shippers:create')")
public void create(@Valid @RequestBody ShipperPojo input)
@@ -83,7 +88,8 @@ public void create(@Valid @RequestBody ShipperPojo input)
}
@Override
- @PutMapping({"", "/"})
+ @PutMapping
+ @Operation(summary = "Replace shippers data.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('shippers:update')")
public void update(@Valid @RequestBody ShipperPojo input, @RequestParam Map requestParams)
@@ -92,7 +98,8 @@ public void update(@Valid @RequestBody ShipperPojo input, @RequestParam Map requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataUserRolesController.java b/src/main/java/org/trebol/api/controllers/DataUserRolesController.java
index 433849c0..3b16e800 100644
--- a/src/main/java/org/trebol/api/controllers/DataUserRolesController.java
+++ b/src/main/java/org/trebol/api/controllers/DataUserRolesController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -53,6 +55,7 @@
@RestController
@RequestMapping("/data/user_roles")
+@Tag(name = "Params management")
@PreAuthorize("isAuthenticated()")
public class DataUserRolesController
extends DataCrudGenericController {
@@ -68,14 +71,16 @@ public DataUserRolesController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List user roles.")
@PreAuthorize("hasAuthority('user_roles:read')")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
return super.readMany(allRequestParams);
}
@Override
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Define new user roles.")
@ResponseStatus(CREATED)
@PreAuthorize("hasAuthority('user_roles:create')")
public void create(@Valid @RequestBody UserRolePojo input)
@@ -84,7 +89,8 @@ public void create(@Valid @RequestBody UserRolePojo input)
}
@Override
- @PutMapping({"", "/"})
+ @PutMapping
+ @Operation(summary = "Replace user roles data.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('user_roles:update')")
public void update(@Valid @RequestBody UserRolePojo input, @RequestParam Map requestParams)
@@ -93,7 +99,8 @@ public void update(@Valid @RequestBody UserRolePojo input, @RequestParam Map requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/DataUsersController.java b/src/main/java/org/trebol/api/controllers/DataUsersController.java
index 13661c98..bf199e5a 100644
--- a/src/main/java/org/trebol/api/controllers/DataUsersController.java
+++ b/src/main/java/org/trebol/api/controllers/DataUsersController.java
@@ -21,6 +21,8 @@
package org.trebol.api.controllers;
import com.querydsl.core.types.OrderSpecifier;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -54,6 +56,7 @@
@RestController
@RequestMapping("/data/users")
+@Tag(name = "Users management")
@PreAuthorize("isAuthenticated()")
public class DataUsersController
extends DataCrudGenericController {
@@ -69,14 +72,16 @@ public DataUsersController(
}
@Override
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "List users.")
@PreAuthorize("hasAuthority('users:read')")
public DataPagePojo readMany(@RequestParam Map allRequestParams) {
return super.readMany(allRequestParams);
}
@Override
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Register new users.")
@ResponseStatus(CREATED)
@PreAuthorize("hasAuthority('users:create')")
public void create(@Valid @RequestBody UserPojo input)
@@ -85,7 +90,8 @@ public void create(@Valid @RequestBody UserPojo input)
}
@Override
- @PutMapping({"", "/"})
+ @PutMapping
+ @Operation(summary = "Replace users data.")
@ResponseStatus(NO_CONTENT)
@PreAuthorize("hasAuthority('users:update')")
public void update(@Valid @RequestBody UserPojo input, @RequestParam Map requestParams)
@@ -93,7 +99,8 @@ public void update(@Valid @RequestBody UserPojo input, @RequestParam Map requestParams)
diff --git a/src/main/java/org/trebol/api/controllers/PublicAboutController.java b/src/main/java/org/trebol/api/controllers/PublicAboutController.java
index eee7af27..28836fb8 100644
--- a/src/main/java/org/trebol/api/controllers/PublicAboutController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicAboutController.java
@@ -20,6 +20,8 @@
package org.trebol.api.controllers;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -29,6 +31,7 @@
@RestController
@RequestMapping("/public/about")
+@Tag(name = "About")
public class PublicAboutController {
private final CompanyService companyService;
@@ -38,7 +41,8 @@ public PublicAboutController(CompanyService companyService) {
this.companyService = companyService;
}
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "View information useful to customers regarding the business.")
public CompanyDetailsPojo readCompanyDetails() {
return companyService.readDetails();
}
diff --git a/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java b/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java
index 3f538d3c..671fe865 100644
--- a/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicCheckoutController.java
@@ -22,6 +22,8 @@
import com.querydsl.core.types.Predicate;
import io.jsonwebtoken.lang.Maps;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
@@ -60,6 +62,7 @@
@RestController
@RequestMapping("/public/checkout")
+@Tag(name = "Checkout")
public class PublicCheckoutController {
private final CheckoutService service;
private final OrdersCrudService ordersCrudService;
@@ -89,7 +92,8 @@ public PublicCheckoutController(
* @throws PaymentServiceException If an error happens during the payment
* payment process
*/
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Submit cart contents to request an order and begin a checkout")
@PreAuthorize("hasAuthority('" + AUTHORITY_CHECKOUT + "')")
public PaymentRedirectionDetailsPojo submitCart(@Valid @RequestBody OrderPojo transactionRequest)
throws BadInputException, PaymentServiceException, EntityExistsException {
@@ -106,7 +110,8 @@ public PaymentRedirectionDetailsPojo submitCart(@Valid @RequestBody OrderPojo tr
* @throws EntityNotFoundException If the token does not match that of any "pending" transaction
* @throws PaymentServiceException If an error happens during internal API calls
*/
- @GetMapping({"/validate", "/validate/"})
+ @GetMapping("/validate")
+ @Operation(summary = "Request that an order status be updated after having begun checkout")
public ResponseEntity validateSuccesfulTransaction(@RequestParam Map transactionData)
throws BadInputException, EntityNotFoundException, PaymentServiceException, MailingServiceException {
if (!transactionData.containsKey(WEBPAY_SUCCESS_TOKEN_HEADER_NAME)) { // success
@@ -133,7 +138,8 @@ public ResponseEntity validateSuccesfulTransaction(@RequestParam Map validateAbortedTransaction(@RequestParam Map transactionData)
throws BadInputException, EntityNotFoundException, PaymentServiceException {
diff --git a/src/main/java/org/trebol/api/controllers/PublicReceiptController.java b/src/main/java/org/trebol/api/controllers/PublicReceiptController.java
index 5a9c634e..a218376f 100644
--- a/src/main/java/org/trebol/api/controllers/PublicReceiptController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicReceiptController.java
@@ -20,6 +20,8 @@
package org.trebol.api.controllers;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -34,6 +36,7 @@
@RestController
@RequestMapping("/public/receipt")
+@Tag(name = "Checkout")
public class PublicReceiptController {
private final ReceiptService receiptService;
@@ -44,7 +47,16 @@ public PublicReceiptController(
this.receiptService = receiptService;
}
- @GetMapping({"/{token}", "/{token}/"})
+ /**
+ * Fetch result of transaction after it has been confirmed and validated
+ *
+ * @param token The token used during the transaction
+ * @return An object with all available data about the transaction
+ * @throws BadInputException when an empty token is provided
+ * @throws EntityNotFoundException when no transaction matches the provided token
+ */
+ @GetMapping("/{token}")
+ @Operation(summary = "View a summary of an order once complete or rejected")
public ReceiptPojo fetchReceiptById(@PathVariable("token") String token)
throws BadInputException, EntityNotFoundException {
if (StringUtils.isBlank(token)) {
diff --git a/src/main/java/org/trebol/api/controllers/PublicRegisterController.java b/src/main/java/org/trebol/api/controllers/PublicRegisterController.java
index f7edc5d2..65a1abd0 100644
--- a/src/main/java/org/trebol/api/controllers/PublicRegisterController.java
+++ b/src/main/java/org/trebol/api/controllers/PublicRegisterController.java
@@ -20,6 +20,8 @@
package org.trebol.api.controllers;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -34,6 +36,7 @@
@RestController
@RequestMapping("/public/register")
+@Tag(name = "User Accounts")
public class PublicRegisterController {
private final RegistrationService registrationService;
@@ -44,7 +47,8 @@ public PublicRegisterController(
this.registrationService = registrationService;
}
- @PostMapping({"", "/"})
+ @PostMapping
+ @Operation(summary = "Request creation of new user account.")
public void register(@Valid @RequestBody RegistrationPojo userProfile)
throws BadInputException, EntityExistsException {
this.registrationService.register(userProfile);
diff --git a/src/main/java/org/trebol/api/controllers/RootController.java b/src/main/java/org/trebol/api/controllers/RootController.java
index f4615c3d..1321b6de 100644
--- a/src/main/java/org/trebol/api/controllers/RootController.java
+++ b/src/main/java/org/trebol/api/controllers/RootController.java
@@ -20,14 +20,18 @@
package org.trebol.api.controllers;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
+@Tag(name = "Health check")
public class RootController {
- @GetMapping({"", "/"})
+ @GetMapping
+ @Operation(summary = "Non-operating endpoint.")
public ResponseEntity defaultMapping() {
return ResponseEntity.ok().build();
}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index fb1b9d6c..1b6c67ce 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -35,6 +35,14 @@ trebol.api.able-to-edit-orders-after-being-processed=false
trebol.validation.id-number-regexp=^\d{7,9}[\dk]$
trebol.validation.phonenumber-regexp=^\\+(?:[0-9] ?){6,14}[0-9]$
##############################
+# SPRINGDOC OPENAPI
+## Disallow generation of OpenAPI specification
+#springdoc.api-docs.enabled=false
+#springdoc.api-docs.path=/v3/api-docs
+## Disallow Swagger UI interface (for API navigation and testing)
+#springdoc.swagger-ui.enabled=false
+#springdoc.swagger-ui.path=/swagger-ui/index.html
+##############################
# SECURITY
## The private key to encrypt and decrypt JWTs with
trebol.security.jwt-secret-key=YOU.SHOULD.PROVIDE.YOUR.OWN.SECRET.KEY.THIS.IS.JUST.A.PLACEHOLDDER