This is a Spring boot application, where as I mentioned in subject "appConfig" root element is missing from the response when I added Swagger. Any Help on this forum will be appreciated.
Here is my response object class:
#JsonRootName(value = "appConfig")
public class AppConfig {
// Using lombok for getter setters
#Getter
#Setter
#JsonProperty("toggles")
private List<Toggle> toggles;
#Getter
#Setter
#JsonProperty("resources")
private List<Resource> resources;
This is my restController
#RequestMapping(value = "/appConfig", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE })
#ResponseStatus(HttpStatus.OK)
public AppConfig appConfig() {
final AppConfig appConfig =delegate.getAppConfig();
return appConfig;
}
This is what I am getting in the response
//MISSING appConfig root element !!!!
{
"resources": [
{
"lastUpdateTimeStamp": "string",
"resourceName": "string"
}
],
"toggles": [
{
"name": "string",
"state": true
}
]
}
This is my POM dependency for Swagger:
<!-- Swagger dependencies -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
<scope>compile</scope>
</dependency>
This is my Swagger Configuration class:
#Configuration
#EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
#Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
private ApiInfo apiInfo() {
return new ApiInfo(
"Blah",
"Blah",
"Blah",
"Terms of service",
new Contact("Blah Administrator", "URL", "Email"),
"License of API", "API license URL");
}
Work around which is UGLY! is define a Dummy response object and wrap your response inside it. So Swagger strips that off and gives the answer what is expected. Still looking for an answer!
Enable these properties at your ObjectMapper configuration:
jsonObjectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
jsonObjectMapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
I got same problem, before using swagger i had response CustomResponse class with getter and setters:
public class CustomResponse<T> {
private T data;
private String message;
}
and response looked liked this:
{
"CustomResponse" : {
"data" : {
"prop" : "prop",
"prop 1" : "prop1",
},
"message" : "true",
}
}
after implementing swagger result is like this:
{
"data" : {
"prop" : "prop",
"prop 1" : "prop1",
},
"message" : "true"
}
tried to add #JsonRootName("CustomResponse") but result is same.
here is swagger config:
#Bean
public Docket productApi() {
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.additionalModels(typeResolver.resolve(CustomResponse.class))
.genericModelSubstitutes(CustomResponse.class)
.select().apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
also tried #amseager solution:
#Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
return mapper;
}
is there any way that to return response with root name.
I was facing the same issues using OpenApi Swagger , I've fixed it by adding a OpenApiCustomiser.
To avoid duplicated answer , I posted the solution Here
Related
I have a yaml file to generate my endpoints based on the OpenAPI principle, but when I open my swagger-ui I see:
openapi: 3.0.2
info:
....
....
paths:
/cities:
get:
tags:
- Cities
summary: Get all cities
operationId: getAllCities
responses:
200:
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/City'
404:
description: Cities not found
content: {}
and the swagger config look like this:
#Configuration
#EnableSwagger2
public class Swagger2Config {
public static final String REST_PACKAGE = "package";
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage(REST_PACKAGE))
.paths(PathSelectors.any())
.build();
}
}
What I'm missing to remove cities-api-controller from swagger ui ?
public class Swagger2Config {
public static final String REST_PACKAGE = "package";
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage(REST_PACKAGE))
.paths(regex("/*.*"))
.build();
}
}
In swagger-ui, I want to add authorization token to request header.
I almost looked at every post in here and other sites. Still cannot make it work as expected. I tried different solutions but nothing changed.
My current implementation according to this offical spring issue:
XController.java:
#ApiOperation(
value = "Yeni Üye Tanımlama Servisi",
notes = "Platformlar tarafından iletilen üye bilgilerinin kaydedilmesini sağlayan servistir.",
response = KfsResponse.class
, authorizations = { #Authorization(value="Authorization") })
SwaggerConfig.java:
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(Predicates.or(RequestHandlerSelectors.basePackage("tr.com.mkk.kfs.kfs.web"), RequestHandlerSelectors.basePackage("tr.com.mkk.kfs.kfs.model.infos")))
.paths(PathSelectors.any()).build()
.apiInfo(apiEndPointsInfo())
.securitySchemes(Arrays.asList(apiKey()))
.securityContexts(Arrays.asList(securityContext));
}
private ApiKey apiKey() {
return new ApiKey("Authorization", "Authorization", "header");
}
SecurityReference securityReference = SecurityReference.builder()
.reference("Authorization")
.scopes(new AuthorizationScope[0])
.build();
SecurityContext securityContext = SecurityContext.builder()
.securityReferences(Arrays.asList(securityReference))
.build();
pom.xml:
<springfox.version>2.9.2</springfox.version>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-bean-validators</artifactId>
<version>${springfox.version}</version>
</dependency>
Result is always the same:
some solutions, has been pointed out working, I tried:
https://github.com/springfox/springfox/issues/2661,
https://github.com/springfox/springfox/issues/2194,
https://stackoverflow.com/a/58720077/7831244,
https://stackoverflow.com/a/52868853/7831244.
You can set Authorization header to docket using ParameterBuilder as shown below
#Configuration
#EnableSwagger2
public class SwaggerConfiguration {
#Value("${title:title}")
private String title;
#Value("${description:description")
private String description;
#Value("${version:0.0.1}")
private String version;
ApiInfo apiInfo() {
return new ApiInfoBuilder().title(title).description(description).version(version).build();
}
#Bean
public Docket api() {
Docket docket;
docket = new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("com.controller")).paths(PathSelectors.any()).build()
.apiInfo(apiInfo());
docket.globalOperationParameters(
Arrays.asList(
new ParameterBuilder().name("Authorization")
.description("Authorization details for security (JWT token or BasicAuth)")
.modelRef(new ModelRef("String")).parameterType("header").required(false).build()));
return docket;
}
}
I am working on Java Spring application with frontend on Angular but I faced issue that I can't resolve without yours help. When I am making requests from Angular to Java only GET ones are passing but POST, DELETE and POST return following error
Access to XMLHttpRequest at 'http://localhost:8080/patient' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Controler
#Controller
#RequestMapping("/patient")
#CrossOrigin(origins = "*", maxAge = 3600)
public class PatientController {
private PatientService patientService;
#Autowired
public PatientController(PatientService patientService) {
this.patientService = patientService;
}
#GetMapping
public ResponseEntity<Iterable<Patient>> getPatient() {
return new ResponseEntity<>(patientService.findAll(), HttpStatus.OK);
}
#PostMapping
public ResponseEntity<Iterable<Patient>> postPatient() {
return new ResponseEntity<>(patientService.findAll(), HttpStatus.OK);
}
#PutMapping
public ResponseEntity<Iterable<Patient>> putPatient() {
return new ResponseEntity<>(patientService.findAll(), HttpStatus.OK);
}
#DeleteMapping
public ResponseEntity<Iterable<Patient>> deletePatient() {
return new ResponseEntity<>(patientService.findAll(), HttpStatus.OK);
}
}
Angular service
getPatients() {
this.http.post(AppComponent.apiUrl + '/patient', this.httpOptions)
.subscribe(data => {
console.log(data);
});
}
proxy.conf.json
{ "/api*": {
"target":"http://localhost:8080",
"secure":false,
"logLevel":"debug",
"changeOrigin": true
}
}
Thank you in advance!
Not need to set origins=* in #CrossOrigin annotation, by default all origins are permited.
You tried to put the annotation at method level?
You could try this:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
#EnableWebMvc
public class CorsConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("https://localhost:4200")
.allowCredentials(true);
}
}
And make sure that your angular client sends his credentials:
httpOptions = {
withCredentials: true,
...
}
Well, I resolved the issue.
I don't know why but CORS Fitler that is quite popular resolution for issues like that doesn't changed anything neiher the proxy config but adding CorsConfigurationSource bean and following lines to configure method resolved the problem.
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//Controlling access
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
...
.and()
.cors()
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Also the second one which was working for me was to add a following class:
#Configuration
public class WebConfiguration implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedMethods("*")
.allowedHeaders("*")
.allowedOrigins("*")
.allowCredentials(false);
}
}
But in this solution is also essential to add .and().cors() lines into security config.
This is a very annoying configuration of Angular. Just allowing cross origins wouldn't be enough. You also would need to allow methods and some headers. This configuration helped me:
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Value("${angular}")
private String angularOrigin;
#Bean
public WebMvcConfigurer corsConfigurer(){
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedOrigins(angularOrigin)
.allowedHeaders("Authorization", "Cache-Control", "Content-Type", "Accept", "X-Requested-With", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Origin")
.exposedHeaders("Access-Control-Expose-Headers", "Authorization", "Cache-Control", "Content-Type", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Origin")
.allowedMethods("PUT","GET","POST","DELETE","OPTIONS");
}
};
}
}
Also notice that there is an OPTION HTTP method that should be allowed.
I have been trying to add authorization in requests that I try from swagger-ui, but in the request, the authorization header is always coming as null.
This is what I have done.
private ApiKey apiKey() {
return new ApiKey("apiKey", "Authorization",
"header"); //`apiKey` is the name of the APIKey, `Authorization` is the key in the request header
}
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select().apis(RequestHandlerSelectors.basePackage("com.example.app"))
.paths(PathSelectors.any()).build().apiInfo(apiInfo()).securitySchemes(Arrays.asList(apiKey()));
}
Can anyone please give some pointers? Thanks.
You can try this SwaggerConfig
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).paths(PathSelectors.any())
.build().securitySchemes(Lists.newArrayList(apiKey()));
}
private ApiKey apiKey() {
return new ApiKey("AUTHORIZATION", "api_key", "header");
}
}
I used swagger 2.9.2 in my spring boot app.
localhost:8080/api-docs works fine.
However, localhost:8080/swagger-ui.html returns writelabel error.
localhost:8080/v2/swagger-ui.html and localhost:8080/api/swagger-ui.html return the same error.
I must have missed something simple. Thanks.
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed Aug 22 10:05:48 CDT 2018
There was an unexpected error (type=Not Found, status=404).
No message available
In build.gradle, I have dependency of springfox.
compile("io.springfox:springfox-swagger2:2.9.2")
compile("io.springfox:springfox-swagger-ui:2.9.2")
swaggerconfig.java
#Configuration
#EnableSwagger2
public class SwaggerConfig{
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage(MyServiceController.class.getPackage().getName()))
//.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
.paths(PathSelectors.ant("/api/**"))
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
String description = "Company - My API";
return new ApiInfoBuilder()
.title("REST API")
.description(description)
.version("1.0")
.build();
}
MyServiceController.java
#ApiOperation(value = "some description",
response = MyServiceResponse.class)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "ok"),
#ApiResponse(code = 400, message = "Bad Request"),
#ApiResponse(code = 401, message = "not authorized"),
#ApiResponse(code = 403, message = "not authenticated"),
#ApiResponse(code = 404, message = "The resource you were trying to reach is not found"),
#ApiResponse(code=500, message = "Interval Server Error")
})
#RequestMapping(method = RequestMethod.POST, value = "/api/component/operation", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
#ResponseBody
{
do something
}
Hey I am using Spring boot 2.1.4, Swagger 2.9.2, I faced the same issue and got resolved by the following:
It seems that you have the required dependencies so this is not the issue.
I think the issue that you have to implement WebMvcConfigure and override addResourceHandlers method:
#Configuration
#EnableSwagger2
public class SwaggerConfig implements WebMvcConfigurer {
// your Docket and ApiInfo methods
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
Just try to add it and Share what happen with you.
Return the Docket bean like below :
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
and add #RestController annotation above your controller class
So if u have correctly written the swaggerConfig code also added the right dependencies and still getting error
The ultimate solution is
You need to have perfect combination of swagger version and spring boot version
Just change the spring boot and swagger version as below
Check in your pom.xml or gradle build
Spring boot version :- <version>1.4.1.RELEASE</version>
Swagger and Sawgger ur version:- <version>2.2.2</version>
There are other combinations available but that u need to try on trial basis
I have the same problem, and solve with this Docket bean config:
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build()
.apiInfo(this.apiInfo());
}
it works for me.
I faced the same issue and got resolved by the following
You can use one dependency:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
SwaggerConfig class like below :
#Configuration
#EnableSwagger2
public class SwaggerConfig implements WebMvcConfigurer {
#Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2);
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
do not use #EnableSwagger2 3.0 version
http://localhost:8080/swagger-ui/index.html