Skip to content
Snippets Groups Projects
Unverified Commit 14c5cfcd authored by Martin Weise's avatar Martin Weise
Browse files

Added swagger documentation to the table service, fixed some unintended...

Added swagger documentation to the table service, fixed some unintended dependencies in the docker-compose.yml file
parent fdcc08a8
No related branches found
No related tags found
2 merge requests!81New stable release,!53Added swagger documentation to the table service, fixed some unintended...
Showing
with 96 additions and 110 deletions
......@@ -94,6 +94,10 @@ services:
depends_on:
fda-container-service:
condition: service_healthy
fda-broker-service:
condition: service_healthy
fda-authentication-service:
condition: service_healthy
logging:
driver: json-file
......@@ -134,6 +138,8 @@ services:
depends_on:
fda-discovery-service:
condition: service_healthy
fda-metadata-db:
condition: service_healthy
logging:
driver: json-file
......@@ -156,6 +162,8 @@ services:
depends_on:
fda-table-service:
condition: service_healthy
fda-authentication-service:
condition: service_healthy
logging:
driver: json-file
......@@ -178,7 +186,11 @@ services:
- /var/run/docker.sock:/var/run/docker.sock
- /tmp:/tmp
depends_on:
fda-database-service:
fda-authentication-service:
condition: service_healthy
fda-search-service:
condition: service_started
fda-broker-service:
condition: service_healthy
logging:
driver: json-file
......@@ -199,6 +211,10 @@ services:
depends_on:
fda-query-service:
condition: service_healthy
fda-authentication-service:
condition: service_healthy
logging:
driver: json-file
fda-analyse-service:
restart: on-failure
......
......@@ -28,8 +28,6 @@
<mapstruct.version>1.4.2.Final</mapstruct.version>
<docker.version>3.2.7</docker.version>
<testcontainers.version>1.15.2</testcontainers.version>
<swagger.version>2.1.7</swagger.version>
<springfox.version>3.0.0</springfox.version>
<jacoco.version>0.8.7</jacoco.version>
<opencsv.version>5.4</opencsv.version>
<super-csv.version>2.4.0</super-csv.version>
......@@ -193,17 +191,6 @@
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>${springfox.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
<version>2.4.21</version>
</dependency>
</dependencies>
<build>
......
......@@ -7,12 +7,10 @@ import org.springframework.data.elasticsearch.repository.config.EnableElasticsea
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import springfox.documentation.oas.annotations.EnableOpenApi;
@SpringBootApplication
@EnableJpaAuditing
@EnableOpenApi
@SpringBootApplication
@EnableTransactionManagement
@EnableElasticsearchRepositories(basePackages = {"at.tuwien.repository.elastic"})
@EnableJpaRepositories(basePackages = {"at.tuwien.repository.jpa"})
......
package at.tuwien.config;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springdoc.core.GroupedOpenApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.Collections;
@Configuration
@EnableOpenApi
public class SwaggerConfig {
@Value("${app.version:unknown}")
private String version;
@Bean
public Docket tableApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.paths(PathSelectors.ant("/api/**"))
.build();
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("Database Repository Table Service API")
.contact(new Contact()
.name("Prof. Andreas Rauber")
.email("andreas.rauber@tuwien.ac.at"))
.description("Service that manages the tables")
.version(version)
.license(new License()
.name("Apache 2.0")
.url("https://www.apache.org/licenses/LICENSE-2.0")))
.externalDocs(new ExternalDocumentation()
.description("Wiki Documentation")
.url("https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/wikis"));
}
private ApiInfo apiInfo() {
return new ApiInfo("FDA-Table-Service API",
"Service API for table service",
"1.0",
null,
new Contact("Ao.Univ.Prof. Andreas Rauber", "http://www.ifs.tuwien.ac.at/~andi/", "rauber@ifs.tuwien.ac.at"),
"API license",
null,
Collections.emptyList());
@Bean
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group("table-service")
.pathsToMatch("/api/**")
.build();
}
}
......@@ -6,11 +6,8 @@ import at.tuwien.exception.*;
import at.tuwien.mapper.TableMapper;
import at.tuwien.service.MessageQueueService;
import at.tuwien.service.TableService;
import at.tuwien.service.impl.RabbitMqService;
import at.tuwien.service.impl.TableServiceImpl;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
......@@ -43,11 +40,7 @@ public class TableEndpoint {
@GetMapping
@Transactional(readOnly = true)
@ApiOperation(value = "List all tables", notes = "Lists the tables in the metadata database for this database.")
@ApiResponses({
@ApiResponse(code = 200, message = "All tables are listed."),
@ApiResponse(code = 401, message = "Not authorized to list all tables."),
})
@Operation(summary = "List all tables", security = @SecurityRequirement(name = "bearerAuth"))
public ResponseEntity<List<TableBriefDto>> findAll(@NotNull @PathVariable("id") Long id,
@NotNull @PathVariable("databaseId") Long databaseId)
throws DatabaseNotFoundException {
......@@ -60,15 +53,7 @@ public class TableEndpoint {
@PostMapping
@Transactional
@PreAuthorize("hasRole('ROLE_RESEARCHER')")
@ApiOperation(value = "Create a table", notes = "Creates a new table for a database, requires a running container.")
@ApiResponses({
@ApiResponse(code = 201, message = "The table was created."),
@ApiResponse(code = 400, message = "The creation form contains invalid data."),
@ApiResponse(code = 401, message = "Not authorized to create a tables."),
@ApiResponse(code = 404, message = "The database does not exist."),
@ApiResponse(code = 405, message = "The container is not running."),
@ApiResponse(code = 409, message = "The table name already exists."),
})
@Operation(summary = "Create a table", security = @SecurityRequirement(name = "bearerAuth"))
public ResponseEntity<TableBriefDto> create(@NotNull @PathVariable("id") Long id,
@NotNull @PathVariable("databaseId") Long databaseId,
@NotNull @Valid @RequestBody TableCreateDto createDto)
......@@ -84,12 +69,7 @@ public class TableEndpoint {
@GetMapping("/{tableId}")
@Transactional(readOnly = true)
@ApiOperation(value = "Get information about table", notes = "Lists the information of a table from the metadata database for this database.")
@ApiResponses({
@ApiResponse(code = 200, message = "All tables are listed."),
@ApiResponse(code = 401, message = "Not authorized to list all tables."),
@ApiResponse(code = 404, message = "Table not found in metadata database."),
})
@Operation(summary = "Get information about table", security = @SecurityRequirement(name = "bearerAuth"))
public ResponseEntity<TableDto> findById(@NotNull @PathVariable("id") Long id,
@NotNull @PathVariable("databaseId") Long databaseId,
@NotNull @PathVariable("tableId") Long tableId)
......@@ -103,13 +83,7 @@ public class TableEndpoint {
@PutMapping("/{tableId}")
@Transactional
@ApiOperation(value = "Update a table", notes = "Update a table in the database.")
@ApiResponses({
@ApiResponse(code = 200, message = "Updated the table."),
@ApiResponse(code = 400, message = "The update form contains invalid data."),
@ApiResponse(code = 401, message = "Not authorized to update tables."),
@ApiResponse(code = 404, message = "The table is not found in database."),
})
@Operation(summary = "Update a table", security = @SecurityRequirement(name = "bearerAuth"))
public ResponseEntity<TableBriefDto> update(@NotNull @PathVariable("id") Long id,
@NotNull @PathVariable("databaseId") Long databaseId,
@NotNull @PathVariable("tableId") Long tableId) {
......@@ -120,12 +94,7 @@ public class TableEndpoint {
@DeleteMapping("/{tableId}")
@Transactional
@PreAuthorize("hasRole('ROLE_DEVELOPER') or hasRole('ROLE_DATA_STEWARD')")
@ApiOperation(value = "Delete a table", notes = "Delete a table in the database.")
@ApiResponses({
@ApiResponse(code = 200, message = "Deleted the table."),
@ApiResponse(code = 401, message = "Not authorized to delete tables."),
@ApiResponse(code = 404, message = "The table is not found in database."),
})
@Operation(summary = "Delete a table", security = @SecurityRequirement(name = "bearerAuth"))
@ResponseStatus(HttpStatus.OK)
public void delete(@NotNull @PathVariable("id") Long id,
@NotNull @PathVariable("databaseId") Long databaseId,
......
......@@ -7,24 +7,27 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@ControllerAdvice
public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
@ExceptionHandler({AmqpException.class})
public ResponseEntity<Object> handle(AmqpException e, WebRequest request) {
public ResponseEntity<ApiErrorDto> handle(AmqpException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.BAD_REQUEST)
.status(HttpStatus.NOT_ACCEPTABLE)
.message(e.getLocalizedMessage())
.code("error.amqp.queue")
.build();
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
}
@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler({ArbitraryPrimaryKeysException.class})
public ResponseEntity<Object> handle(ArbitraryPrimaryKeysException e, WebRequest request) {
public ResponseEntity<ApiErrorDto> handle(ArbitraryPrimaryKeysException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.BAD_REQUEST)
.message(e.getLocalizedMessage())
......@@ -33,8 +36,9 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
}
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
@ExceptionHandler({DatabaseConnectionException.class})
public ResponseEntity<Object> handle(DatabaseConnectionException e, WebRequest request) {
public ResponseEntity<ApiErrorDto> handle(DatabaseConnectionException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.METHOD_NOT_ALLOWED)
.message(e.getLocalizedMessage())
......@@ -43,8 +47,9 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
}
@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler({DatabaseNotFoundException.class})
public ResponseEntity<Object> handle(DatabaseNotFoundException e, WebRequest request) {
public ResponseEntity<ApiErrorDto> handle(DatabaseNotFoundException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.NOT_FOUND)
.message(e.getLocalizedMessage())
......@@ -53,8 +58,9 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({DataProcessingException.class})
public ResponseEntity<Object> handle(DataProcessingException e, WebRequest request) {
public ResponseEntity<ApiErrorDto> handle(DataProcessingException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.BAD_REQUEST)
.message(e.getLocalizedMessage())
......@@ -63,8 +69,9 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({FileStorageException.class})
public ResponseEntity<Object> handle(FileStorageException e, WebRequest request) {
public ResponseEntity<ApiErrorDto> handle(FileStorageException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.BAD_REQUEST)
.message(e.getLocalizedMessage())
......@@ -73,28 +80,31 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({ImageNotSupportedException.class})
public ResponseEntity<Object> handle(ImageNotSupportedException e, WebRequest request) {
public ResponseEntity<ApiErrorDto> handle(ImageNotSupportedException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.CONFLICT)
.status(HttpStatus.BAD_REQUEST)
.message(e.getLocalizedMessage())
.code("error.database.image")
.build();
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({PaginationException.class})
public ResponseEntity<Object> handle(PaginationException e, WebRequest request) {
public ResponseEntity<ApiErrorDto> handle(PaginationException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.CONFLICT)
.status(HttpStatus.BAD_REQUEST)
.message(e.getLocalizedMessage())
.code("error.database.pagination")
.build();
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
}
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler({TableNameExistsException.class})
public ResponseEntity<Object> handle(TableNameExistsException e, WebRequest request) {
public ResponseEntity<ApiErrorDto> handle(TableNameExistsException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.CONFLICT)
.message(e.getLocalizedMessage())
......@@ -103,8 +113,9 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({TableMalformedException.class})
public ResponseEntity<Object> handle(TableMalformedException e, WebRequest request) {
public ResponseEntity<ApiErrorDto> handle(TableMalformedException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.BAD_REQUEST)
.message(e.getLocalizedMessage())
......@@ -113,8 +124,9 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus());
}
@ResponseStatus(HttpStatus.NOT_FOUND)
@ExceptionHandler({TableNotFoundException.class})
public ResponseEntity<Object> handle(TableNotFoundException e, WebRequest request) {
public ResponseEntity<ApiErrorDto> handle(TableNotFoundException e, WebRequest request) {
final ApiErrorDto response = ApiErrorDto.builder()
.status(HttpStatus.NOT_FOUND)
.message(e.getLocalizedMessage())
......
app.version: '@project.version@'
spring:
main.banner-mode: off
datasource:
......
app.version: '@project.version@'
spring:
main.banner-mode: off
datasource:
......
......@@ -2,6 +2,8 @@ package at.tuwien.config;
import at.tuwien.auth.AuthTokenFilter;
import at.tuwien.gateway.AuthenticationServiceGateway;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
......@@ -21,6 +23,12 @@ import javax.servlet.http.HttpServletResponse;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@SecurityScheme(
name = "bearerAuth",
type = SecuritySchemeType.HTTP,
bearerFormat = "JWT",
scheme = "bearer"
)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final AuthenticationServiceGateway authenticationServiceGateway;
......@@ -58,16 +66,10 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
http.authorizeRequests()
/* our public endpoints */
.antMatchers(HttpMethod.GET, "/api/container/**/database/**/table/**").permitAll()
.antMatchers("/v2/api-docs",
"/configuration/ui",
"/swagger-resources",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**",
"/swagger-resources/configuration/ui",
"/swagger-ui.html",
.antMatchers("/v3/api-docs.yaml",
"/v3/api-docs/**",
"/swagger-ui/**").permitAll()
"/swagger-ui/**",
"/swagger-ui.html").permitAll()
/* our private endpoints */
.anyRequest().authenticated();
/* add JWT token filter */
......
......@@ -13,19 +13,14 @@ import at.tuwien.entities.database.Database;
import at.tuwien.entities.database.table.Table;
import at.tuwien.entities.database.table.columns.TableColumn;
import at.tuwien.entities.database.table.columns.TableColumnType;
import at.tuwien.entities.database.table.columns.concepts.ColumnConcept;
import at.tuwien.entities.database.table.columns.concepts.Concept;
import at.tuwien.exception.ImageNotSupportedException;
import at.tuwien.exception.TableMalformedException;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.Named;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.text.Normalizer;
import java.util.*;
import java.util.regex.Pattern;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment