diff --git a/pom.xml b/pom.xml
index 819389e3..966b7d27 100644
--- a/pom.xml
+++ b/pom.xml
@@ -287,6 +287,15 @@
org.springframework.boot
spring-boot-starter-validation
+
+
+
+ org.springdoc
+ springdoc-openapi-ui
+ 1.5.10
+
+
+
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceConfig.java b/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceConfig.java
index c1f79837..1c245cab 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceConfig.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceConfig.java
@@ -16,9 +16,27 @@ import org.springframework.context.annotation.Lazy;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
+import io.swagger.v3.oas.annotations.OpenAPIDefinition;
+import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
+import io.swagger.v3.oas.annotations.info.Info;
+import io.swagger.v3.oas.annotations.security.OAuthFlow;
+import io.swagger.v3.oas.annotations.security.OAuthFlows;
+import io.swagger.v3.oas.annotations.security.SecurityScheme;
@Configuration
@WebServiceProfile
+@OpenAPIDefinition(info = @Info(title = "SEB Server", version = "v1"))
+@SecurityScheme(
+ name = "oauth2",
+ type = SecuritySchemeType.OAUTH2,
+ bearerFormat = "JWT",
+ flows = @OAuthFlows(
+ password = @OAuthFlow(
+ tokenUrl = "/oauth/token"
+
+ )
+
+ ))
public class WebserviceConfig {
@Lazy
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java
index 39a8e0d6..d539426d 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java
@@ -25,7 +25,6 @@ import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@@ -54,12 +53,18 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
/** Abstract Entity-Controller that defines generic Entity rest API endpoints that are supported
* by all entity types.
*
* @param The concrete Entity domain-model type used on all GET, PUT
* @param The concrete Entity domain-model type used for POST methods (new) */
+@SecurityRequirement(name = "oauth2")
public abstract class EntityController {
protected final AuthorizationService authorization;
@@ -129,6 +134,39 @@ public abstract class EntityController {
* descending sort order.
* @param allRequestParams a MultiValueMap of all request parameter that is used for filtering.
* @return Page of domain-model-entities of specified type */
+ @Operation(
+ summary = "Get a page of the specific domain entity. Sorting and filtering is applied before paging",
+ requestBody = @RequestBody(
+ content = { @Content(mediaType = MediaType.APPLICATION_FORM_URLENCODED_VALUE) }),
+ parameters = {
+ @Parameter(
+ name = Page.ATTR_PAGE_NUMBER,
+ description = "The number of the page to get from the whole list. If the page does not exists, the API retruns with the first page."),
+ @Parameter(
+ name = Page.ATTR_PAGE_SIZE,
+ description = "The size of the page to get."),
+ @Parameter(
+ name = Page.ATTR_SORT,
+ description = "the sort parameter to sort the list of entities before paging\n"
+ + "the sort parameter is the name of the entity-model attribute to sort with a leading '-' sign for\n"
+ + "descending sort order. Note that not all entity-model attribute are suited for sorting while the most are.",
+ example = "-name"),
+ @Parameter(
+ name = API.PARAM_INSTITUTION_ID,
+ description = "The institution identifier of the request.\n"
+ + "Default is the institution identifier of the institution of the current user"),
+ @Parameter(
+ name = "filterCriteria",
+ description = "Additional filter criterias \n" +
+ "The filter criteria attributes accepted by this API depend on the actual entity model (domain entity)\n"
+ + "and are query of the form [domain-attribute-name]=[filter-value]. E.g.: name=abc or type=EXAM.\n"
+ + "For OpenAPI 3 input please use the form: {\"columnName\":\"filterValue\"}\n"
+ + "Usually filter attributes of text type are treated as SQL wildcard with %[text]% to filter all text containing\n"
+ + "a given text-snippet.",
+ example = "{\"name\":\"ethz\"}",
+ required = false,
+ allowEmptyValue = true)
+ })
@RequestMapping(
method = RequestMethod.GET,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
@@ -141,13 +179,13 @@ public abstract class EntityController {
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort,
- @RequestParam final MultiValueMap allRequestParams,
+ @RequestParam final MultiValueMap filterCriteria,
final HttpServletRequest request) {
// at least current user must have read access for specified entity type within its own institution
checkReadPrivilege(institutionId);
- final FilterMap filterMap = new FilterMap(allRequestParams, request.getQueryString());
+ final FilterMap filterMap = new FilterMap(filterCriteria, request.getQueryString());
populateFilterMap(filterMap, institutionId, sort);
return this.paginationService.getPage(
@@ -176,6 +214,28 @@ public abstract class EntityController {
// * GET (names)
// ******************
+ @Operation(
+ summary = "Get a filtered list of specific entity name keys.\n" +
+ "An entity name key is a minimal entity data object with the entity-type, modelId and the name of the entity.",
+ requestBody = @RequestBody(
+ content = { @Content(mediaType = MediaType.APPLICATION_FORM_URLENCODED_VALUE) }),
+ parameters = {
+ @Parameter(
+ name = API.PARAM_INSTITUTION_ID,
+ description = "The institution identifier of the request.\n"
+ + "Default is the institution identifier of the institution of the current user"),
+ @Parameter(
+ name = "filterCriteria",
+ description = "Additional filter criterias \n" +
+ "The filter criteria attributes accepted by this API depend on the actual entity model (domain entity)\n"
+ + "and are query of the form [domain-attribute-name]=[filter-value]. E.g.: name=abc or type=EXAM.\n"
+ + "For OpenAPI 3 input please use the form: {\"columnName\":\"filterValue\"}\n"
+ + "Usually filter attributes of text type are treated as SQL wildcard with %[text]% to filter all text containing\n"
+ + "a given text-snippet.",
+ example = "{\"name\":\"ethz\"}",
+ required = false,
+ allowEmptyValue = true)
+ })
@RequestMapping(
path = API.NAMES_PATH_SEGMENT,
method = RequestMethod.GET,
@@ -186,13 +246,13 @@ public abstract class EntityController {
name = API.PARAM_INSTITUTION_ID,
required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
- @RequestParam final MultiValueMap allRequestParams,
+ @RequestParam final MultiValueMap filterCriteria,
final HttpServletRequest request) {
// at least current user must have read access for specified entity type within its own institution
checkReadPrivilege(institutionId);
- final FilterMap filterMap = new FilterMap(allRequestParams, request.getQueryString());
+ final FilterMap filterMap = new FilterMap(filterCriteria, request.getQueryString());
// if current user has no read access for specified entity type within other institution then its own institution,
// then the current users institutionId is put as a SQL filter criteria attribute to extends query performance
@@ -285,7 +345,7 @@ public abstract class EntityController {
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public T create(
- @RequestParam final MultiValueMap allRequestParams,
+ @RequestParam final MultiValueMap formParams,
@RequestParam(
name = API.PARAM_INSTITUTION_ID,
required = true,
@@ -295,7 +355,7 @@ public abstract class EntityController {
// check write privilege for requested institution and concrete entityType
this.checkWritePrivilege(institutionId);
- final POSTMapper postMap = new POSTMapper(allRequestParams, request.getQueryString())
+ final POSTMapper postMap = new POSTMapper(formParams, request.getQueryString())
.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
final M requestModel = this.createNew(postMap);
diff --git a/src/main/resources/config/application-dev.properties b/src/main/resources/config/application-dev.properties
index b11db757..8194d5a1 100644
--- a/src/main/resources/config/application-dev.properties
+++ b/src/main/resources/config/application-dev.properties
@@ -1,4 +1,4 @@
-spring.profiles.include=dev-ws,dev-gui
+spring.profiles.include=dev-ws
sebserver.test.property=This is the development Setup
diff --git a/src/main/resources/config/application-ws.properties b/src/main/resources/config/application-ws.properties
index 9e6c6799..9c300053 100644
--- a/src/main/resources/config/application-ws.properties
+++ b/src/main/resources/config/application-ws.properties
@@ -40,7 +40,14 @@ sebserver.webservice.distributed=false
sebserver.webservice.http.external.scheme=https
sebserver.webservice.http.external.servername=
sebserver.webservice.http.external.port=
-sebserver.webservice.http.redirect.gui=/gui
+sebserver.webservice.http.redirect.gui=/
+
+### Open API Documentation
+springdoc.swagger-ui.oauth.clientId=guiClient
+springdoc.swagger-ui.oauth.clientSecret=${sebserver.password}
+#springdoc.consumes-to-match=application/json,application/x-www-form-urlencoded
+#springdoc.default-consumes-media-type=application/x-www-form-urlencoded
+springdoc.paths-to-exclude=/exam-api,/exam-api/discovery,/sebserver/error,/sebserver/check,/oauth,/exam-api/v1/*
### webservice API
sebserver.webservice.api.admin.clientId=guiClient
diff --git a/src/main/resources/config/application.properties b/src/main/resources/config/application.properties
index 2f6bd64a..873928af 100644
--- a/src/main/resources/config/application.properties
+++ b/src/main/resources/config/application.properties
@@ -1,5 +1,5 @@
spring.application.name=SEB Server
-spring.profiles.active=ws,gui,dev
+spring.profiles.active=ws,dev
sebserver.version=@sebserver-version@
##########################################################