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