How to do pattern check for an attribute in swagger V3 using spring webflux - spring-boot

I am writing a reactive application using webflux with springdoc-openapi(v 1.4.3). Below is the router class
#Configuration
public class FacilitiesRouter {
#RouterOperation(path = "/facilities", produces = {
MediaType.APPLICATION_JSON_VALUE},
beanClass = FacilitiesHandler.class, method = RequestMethod.GET, beanMethod = "getFacility",
operation = #Operation(operationId = "getFacility", summary = "Get facilities1 by key",
description = "Retrieves one or more facilities1 based on provided keys .",responses = {
#ApiResponse(responseCode = "200", description = "successful operation",
content = #Content(schema = #Schema(implementation = FacilitiesResponse.class)))
},
parameters = {
#Parameter(in = ParameterIn.QUERY, name = "id",required = true)
}
))
#Bean
public RouterFunction<ServerResponse> route(FacilitiesHandler handler) {
return RouterFunctions.route(GET("/facilities"), handler::getFacility);
}
}
Dependency used are
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-core</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>1.4.3</version>
</dependency>
What I am trying is that:
parameter "id" which is Query parameter should follow REGEX [a-zA-Z0-9]{5,15}. So that from swagger if anyone is passing id which does not follow this regex it gives some warning kind of things.
I explored all the suggestions coming in #parameters . It does not have any methods to achieve it. can anyone help me know how to achieve it.

Related

Hateoas - No suitable constructor found for Link(java.lang.String)

For a REST API, in the controller I'm applying hateoas. When adding the part of Link in the methods, I get the follow error:
Cannot resolve constructor 'Link(String)'
In the pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
The code is as follows:
#GetMapping
public #ResponseBody ResponseEntity<List<UserResponseDTO>> get() {
// Retrieve users
List<UserResponseDTO> responseDTOS = new ArrayList<>();
List<User> users = userService.getUsers();
// Convert to responseDTOS
for (User user : users) {
UserResponseDTO userResponseDTO = new UserResponseDTO(user.getId(), user.getFirstName(), user.getLastName());
Link get = new Link("http://localhost:8081/user/").withRel("GET");
userResponseDTO.add(get);
responseDTOS.add(userResponseDTO);
}
return new ResponseEntity<>(responseDTOS, HttpStatus.OK);
}
Does anyone know how to solve this?
Link(String) is deprecated and may be removed in some new version. Also Link(String) uses the protected access modifier meaning you should access it only from the same package.
You can still create the Link using the of static method which by the way is defined with public access modifier.
So it should be
Link get = Link.of("http://localhost:8081/user/").withRel("GET");

How to use resilience4j on calling method?

I tried to use spring retry for Circuit breaking and retry as below and it is working as expected but issue is unable to configure "maxAttempts/openTimeout/resetTimeout" as env variables (error is should be constants). My question is how use resilience4j to achieve the below requirement?
also please suggest there is a way to pass env variables to "maxAttempts/openTimeout/resetTimeout".
#CircuitBreaker(value = {
MongoServerException.class,
MongoSocketException.class,
MongoTimeoutException.class
MongoSocketOpenException.class},
maxAttempts = 2,
openTimeout = 20000L ,
resetTimeout = 30000L)
public void insertDocument(ConsumerRecord<Long, GenericRecord> consumerRecord){
retryTemplate.execute(args0 -> {
LOGGER.info(String.format("Inserting record with key -----> %s", consumerRecord.key().toString()));
BasicDBObject dbObject = BasicDBObject.parse(consumerRecord.value().toString());
dbObject.put("_id", consumerRecord.key());
mongoCollection.replaceOne(<<BasicDBObject with id>>, getReplaceOptions());
return null;
});
}
#Recover
public void recover(RuntimeException t) {
LOGGER.info(" Recovering from Circuit Breaker ");
}
dependencies used are
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
You are not using resilience4j, but spring-retry.
You should adapt the title of your question.
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.waitDurationInOpenState(Duration.ofMillis(20000))
.build();
CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig);
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("mongoDB");
RetryConfig retryConfig = RetryConfig.custom().maxAttempts(3)
.retryExceptions(MongoServerException.class,
MongoSocketException.class,
MongoTimeoutException.class
MongoSocketOpenException.class)
.ignoreExceptions(CircuitBreakerOpenException.class).build();
Retry retry = Retry.of("helloBackend", retryConfig);
Runnable decoratedRunnable = Decorators.ofRunnable(() -> insertDocument(ConsumerRecord<Long, GenericRecord> consumerRecord))
.withCircuitBreaker(circuitBreaker)
.withRetry(retry)
.decorate();
String result = Try.runRunnable(decoratedRunnable )
.recover(exception -> ...).get();

Swagger for Micronaut with maven

I want to switch to the Micronaut framework from Spring Boot 2. And I am struggling with the Swagger settings.
In Spring Boot 2 project I have the following dependencies:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
and SwaggerConfig.class:
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket swagger() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.paths(PathSelectors.any())
.build();
}
private ApiInfo getApiInfo() {
return new ApiInfo("test",
"",
"",
"",
new Contact("", "https://test.test", ""),
"",
"");
}
}
And it works perfectly starting up swagger-ui along with the Spring Boot 2 application.
Which dependencies should I add to maven and which classes should I create to obtain the same result for the Micronaut project?
Assuming the application is already created, add the following to you pom.xml
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger.version}</version>
<scope>compile</scope>
</dependency>
where the property swagger.version is set to 2.0.3
add the following to you annotationProcessorPaths in the maven-compiler-plugin
<path>
<groupId>io.micronaut.configuration</groupId>
<artifactId>micronaut-openapi</artifactId>
<version>${micronaut.version}</version>
</path>
Then add the following to your micronaut router section.
micronaut:
router:
static-resources:
swagger:
paths: classpath:META-INF/swagger
mapping: ${application.api.swagger.path}/**
This will expose your swagger/oas yml file that is generated during compile, provided you use the configuration below. You can of course change the ${application.api.swagger.path} to just be /api-docs/swagger or something to your liking.
As described in the docs, you can also do the following --features=swagger-java to add the above dependecies when you initially create the project.
If you want to render the api-specification from the application itself, then you need to add some more code. The following example is probably more fleshed out than it needs to be, but for my purpose the application serves as a central renderer for swagger/oas specifications.
First add a controller for you swagger needs, and annotate the controller with #Hidden to make sure it doesn't get processed by the annotation processor.
#Hidden
#Controller("/api")
public class SwaggerController {
#Inject
SwaggerConfig config;
#View("swagger/index")
#Get
public SwaggerConfig index() {
return config;
}
}
Then add the following configuration class, which binds the properties from below
#ConfigurationProperties(SwaggerConfig.PREFIX)
public class SwaggerConfig {
public static final String PREFIX = "application.api.swagger";
private String version;
private String layout;
private boolean deepLinking;
private List<URIConfig> urls;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getLayout() {
return layout;
}
public void setLayout(String layout) {
this.layout = layout;
}
public boolean isDeepLinking() {
return deepLinking;
}
public void setDeepLinking(boolean deepLinking) {
this.deepLinking = deepLinking;
}
public List<URIConfig> getUrls() {
return urls;
}
public void setUrls(List<URIConfig> urls) {
this.urls = urls;
}
#ConfigurationProperties(URIConfig.PREFIX)
public static class URIConfig {
static final String PREFIX = "urls";
private String name;
private String url;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
}
The above config class binds the following configuration from application.yml, but needs to be placed before the micronaut specific configuration.
application:
api:
swagger:
path: /api-docs/swagger
version: 3.19.4
layout: StandaloneLayout
deepLinking: true
urls:
- name: ubw-rest
url: /api-docs/swagger/ubw-rest-0.1.yml
When that is done, add the following handlebars/mustache dependency to the pom
<dependency>
<groupId>com.github.jknack</groupId>
<artifactId>handlebars</artifactId>
<version>4.1.0</version>
<scope>runtime</scope>
</dependency>
Under the resources folder, create a folder named swagger, and then create an index.hbs file containing the following.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger-ui</title>
<link rel="icon" type="image/png" href="https://unpkg.com/swagger-ui-dist#{{version}}/favicon-32x32.png">
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist#{{version}}/swagger-ui.css">
<script src="https://unpkg.com/swagger-ui-dist#{{version}}/swagger-ui-standalone-preset.js"></script>
<script src="https://unpkg.com/swagger-ui-dist#{{version}}/swagger-ui-bundle.js"></script>
</head>
<body>
<div id="swagger-ui"></div>
<script>
window.onload = function() {
var ui = SwaggerUIBundle({
urls: [{{#each urls}}
{
name: "{{name}}",
url: "{{url}}"
}{{#unless #last}},{{/unless}}{{/each}}
],
dom_id: '#swagger-ui',
deepLinking: {{deepLinking}},
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "{{layout}}"
});
window.ui = ui
}
</script>
</body>
</html>
Finally, in the application main class, add the #OpenApiDefinition annotation to enable the annotation processor to scan the entire appliaction.
#OpenAPIDefinition(
info = #Info(
title = "swagger-server",
version = "0.1",
description = "My API",
license = #License(name = "Apache 2.0")
)
)
public class Application {
public static void main(String[] args) {
Micronaut.run(Application.class);
}
}
A word of advice regarding the annotation processor as it stands in micronaut 1.0.0 is that public fields on an object will not be exposed, so you need to have getters/setters if you want to see the schema for the input or return values.
If you'd like to try out a running example of the above, I have a repo with the swagger server configuration located here https://github.com/frehov/micronaut-swagger-server which includes the ability to make a post with a list of url and name pairs to be rendered by Swagger.
Micronaut able to automatically generate Swagger YAML definitions from our controller and methods based on these annotations. Add swagger-annotations dependency pom.xml.
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.0.5</version>
</dependency>
Add #OpenAPIDefinition annotation to application's main class.
#OpenAPIDefinition(
info = #Info(
title = "my app",
version = "1.0",
description = "my api",
contact = #Contact(url = "http://something.com", name = "something", email = "something")
)
)
public class Application {
public static void main(String[] args) {
Micronaut.run(Application.class);
}
}
Micronaut generates a Swagger file at target/classes/META-INF/swagger/my-app-1.0.yml. We can expose it outside the application using an HTTP endpoint. Here's the appropriate configuration provided inside the application.yml file.
micronaut:
router:
static-resources:
swagger:
paths: classpath:META-INF/swagger
mapping: /swagger/**
Accesspath http://localhost:8080/swagger/my-app-1.0.yml.
In comparison to Spring Boot, we don't have projects like Swagger
SpringFox for Micronaut, so we need to copy the content to an online
editor in order to see the graphical representation of our Swagger
YAML.
Paste your content of my-app-1.0.yml to https://editor.swagger.io/ and add server to access Swagger UI.
Read Micronaut Doc- https://micronaut-projects.github.io/micronaut-openapi/latest/guide/index.html

How to remove the entire cache, and then pre-populate the cache?

Can someone tell me what is the problem with below implementation. I'm trying to delete the entire cache, secondly, I then want to pre-populate/prime the cache. However, what I've below is only deleting both caches, but not pre-populating/priming the cache, when the two methods are executed. Any idea?
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
#Cacheable(cacheNames = "cacheOne")
List<User> cacheOne() throws Exception {...}
#Cacheable(cacheNames = "cacheOne")
List<Book> cacheTwo() throws Exception {...}
#Caching (
evict = {
#CacheEvict(cacheNames = "cacheOne", allEntries = true),
#CacheEvict(cacheNames = "CacheTwo", allEntries = true)
}
)
void clearAndReloadEntireCache() throws Exception
{
// Trying to reload cacheOne and cacheTwo inside this method
// Is this even possible? if not what is the correct approach?
cacheOne();
cacheTwo();
}
I've spring boot application (v1.4.0), more importantly, utilizing the following dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.0.0</version>
</dependency>
If you call the clearAndReloadEntireCache() method, only this method will be processed by the caching interceptor. Calling other methods of the same object: cacheOne() and cacheTwo() will not cause cache interception at runtime, although both of them are annotated with #Cacheable.
You could achieve desired functionality by reloading cacheOne and cacheTwo with two method calls shown below:
#Caching(evict = {#CacheEvict(cacheNames = "cacheOne", allEntries = true, beforeInvocation = true)},
cacheable = {#Cacheable(cacheNames = "cacheOne")})
public List<User> cleanAndReloadCacheOne() {
return cacheOne();
}
#Caching(evict = {#CacheEvict(cacheNames = "cacheTwo", allEntries = true, beforeInvocation = true)},
cacheable = {#Cacheable(cacheNames = "cacheTwo")})
public List<Book> cleanAndReloadCacheTwo() {
return cacheTwo();
}

Spring boot REST api file upload

I wrote some code to create a REST api to handle customer's infomation and a file from them,I want to save the file they upload to my local disk on server.My code is as below
#RequestMapping(value = "/alg", method = RequestMethod.POST)
public String postUsersNewAlg(#RequestParam(value = "file", required = true) CommonsMultipartFile jarfile,
#RequestParam(value = "username", required = true) String userName,
#RequestParam(value = "output", required = true) String output) {
//other code handles string infos etc.
try {
//get directory path that to save file
String filePath = PathUtil.getOffAlgJarFilePathRoot();
//get file path
String filePathWhole = null;
if (!filePath.endsWith(SeparatorUtils.getFileSeparator())) {
filePathWhole = filePath + SeparatorUtils.getFileSeparator() + algImpl.getOriginalFilename();
}
else {
filePathWhole = filePath + algImpl.getOriginalFilename();
}
FileUtil.copyFile(jarfile, filePath,filePathWhole);
}
catch(Exception e){
e.printStackTrace();
return e.getMessage();
}
}
Problem is a java.lang.NoClassDefFoundError:org/apache/commons/fileupload/FileUploadException] with root cause.So how can I do this?Thanks in advance.
Have you tried this one on pom.xml or add commons-fileupload.jar:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.1</version>
</dependency>

Resources