Swagger basic authorization not working with #Api annotation - java

Swagger basic authorization not working with #Api annotation .But when used with #Apioperation it is working fine . I want to apply basic authorization at controller level rather than at method level .
used like this :
#RestController
#Slf4j
#Api(value="API related ",authorizations = {#Authorization(value="basicAuth")})
#RequestMapping(value="invoices",produces =MediaType.APPLICATION_JSON_UTF8_VALUE)
#SuppressWarnings("rawtypes")
public class InvoiceController {
#SuppressWarnings("unchecked")
#GetMapping
#ApiOperation(value = "${InvoiceController.getAll.notes}", notes="${InvoiceController.getAll.notes}",response = Invoice.class)
#ApiResponses(value = {#ApiResponse(code = 200, message = "Successfully retrieved list of invoices")})
public #ResponseBody ResponseEntity<Response> getAll(#Valid PaginationDto pagination,#Valid InvoiceFilterCriteriaDto filter)
throws GenericServiceException{
}
}
in main class , created Docket like below by mentioning the basic auth :
List<SecurityScheme> schemeList = new ArrayList<>();
schemeList.add(new BasicAuth("basicAuth"));
return new Docket(DocumentationType.SWAGGER_2)
.forCodeGeneration(true)
.produces(new HashSet<>(Arrays.asList( new String[] { MediaType.APPLICATION_JSON_UTF8_VALUE.toString()})))
.apiInfo(apiInfo())
.securitySchemes(schemeList)

Fixed by adding securityContexts to Docket config.
Please refer to https://www.baeldung.com/spring-boot-swagger-jwt

Related

WebFlux Swagger (Open API) integraton - Post Request sample

I have integrated Swagger (OpenAPI) with Spring Webflux as mentioned here: https://springdoc.org/#spring-weblfuxwebmvcfn-with-functional-endpoints using RouterOperation. The integration works fine and is accessible at /swagger-ui.html
However, for POST APIs, I am not seeing the "Request" sample when I click on "Try it out" button. My Post API accepts a Json as Request Body.
How do I configure this ? Can that be done via Annotations along with RouterOperation or something else ?
Edit: Below is my Router class code:
#Configuration
public class MyRouter {
#RouterOperations({
#RouterOperation(path = "/data", beanClass = MyHandler.class, beanMethod = "getData"),
#RouterOperation(path = "/allData", beanClass = MyHandler.class, beanMethod = "getAllData") })
#Bean
public RouterFunction<ServerResponse> route(MyHandler MyHandler) {
return RouterFunctions
.route(RequestPredicates.POST("/data").and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), MyHandler::getData)
.andRoute(RequestPredicates.GET("/allData").and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), MyHandler::getAllData);
}
}
Upon adding RouterOperations annotation I can see the swagger-ui showing both the GET and POST APIs correctly but not the request schema sample.
I also came across yaml / json file to describe this. But I am not getting where to put this file in my application so that swagger-ui uses it.
Finally found it
Using #Operation and #Schema, can define the class that is required as input in request body. This will be shown as sample json structure in Swagger-ui. No other configuration required.
#RouterOperations({
#RouterOperation(
path = "/data", beanClass = MyHandler.class, beanMethod = "getData",
operation = #Operation(
operationId = "opGetData",
requestBody = #RequestBody(required = true, description = "Enter Request body as Json Object",
content = #Content(
schema = #Schema(implementation = ApiRequestBody.class))))),
#RouterOperation(path = "/allData", beanClass = MyHandler.class, beanMethod = "getAllData")})
#Bean
public RouterFunction<ServerResponse> route(MyHandler myHandler) {
return RouterFunctions
.route(RequestPredicates.POST("/data").and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), myHandler::getData)
.andRoute(RequestPredicates.GET("/allData").and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), myHandler::getAllData);
}

Implementation of Swagger core v3 in java

I'm writing some API and I want to integrate Documentation while writing code, so I found Swagger as a good way to to this.
I used Swagger core v3 notations, so my classes are something like:
#RestController
#RequestMapping("/api/v1/bundles")
#OpenAPIDefinition(
info = #Info(
title = "Lifecycle Management RESTful API.",
version = "1",
description = "TODO",
license = #License(name = "Apache 2.0", url = "xxx"),
contact = #Contact(url = "xxx", name = "xx", email = "xxx#xxx.fr")
))
public class RestBundle {
#GetMapping(value = "/{nodeId}",
produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
#Operation(summary = "Get all bundles",
description = "Get all available bundles status from a specific node")
public Something(..) {
//Something ...
}
}
And I create a configuration class:
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("ANF Orchestrator")
.description("REST API for ANF Orchestrator")
.license("Apache 2.0")
.licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
.termsOfServiceUrl("")
.version("1.0.0")
.contact(new Contact("Amine","xxx", "aalaouie#laas.fr"))
.build();
}
}
ANd I want to enable the UI of Swagger to get the documentation, but when I enter to:
.../swagger-ui.html
I get:
Unable to render this definition
The provided definition does not specify a valid version field.
Please indicate a valid Swagger or OpenAPI version field. Supported version fields are swagger: "2.0" and those that match openapi: 3.0.n(for example, openapi: 3.0.0).
Try to extend your SwaggerConfig class with WebMvcConfigurationSupport and override its method called addResourceHandlers with implementation like this:
#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/");
}
On top of class, can you try removing this annotation, as the SwaggerConfig already contains the Docket info.
#OpenAPIDefinition(
info = #Info(
title = "Lifecycle Management RESTful API.",
version = "1",
description = "TODO",
license = #License(name = "Apache 2.0", url = "xxx"),
contact = #Contact(url = "xxx", name = "xx", email = "xxx#xxx.fr")
))

Using RestTemplate in spring-boot returns with 404

I am trying to send a body in a post request in a springboot application using rest template. Here is the controller:(I removed #RequestBody because I used application/x-www-form-urlencoded header)
#RestController
#CrossOrigin
#RequestMapping("/api")
public class SentimentParserController {
#Autowired
private SentimentParserService sentimentParserService;
#RequestMapping(value = "/something", method = RequestMethod.POST, consumes="application/x-www-form-urlencoded")
public ResponseEntity<mcResponse>getTheSentiments( mcSentimentRequestDTO sentimentRequestDTO){
return sentimentParserService.getSentimentsMc(sentimentRequestDTO);
}
}
I want to send the sentimentRequestDTO object(lang, key, and text) as the body in a post request to get the mcResponse:
public mcResponse parseTheSentiments(String text, Languages lang, String key) throws Exception {
RestTemplate restTemplate = new RestTemplate();
String request = "http://localhost:8080";
mcSentimentRequestDTO mSentiments =new mcSentimentRequestDTO(key,"EN",text);
HttpHeaders headers = new HttpHeaders();
headers.add("content-type", "application/x-www-form-urlencoded");
MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
map.add("key", key);
map.add("txt", text);
map.add("lang", Languages.ENGLISH.toString());
HttpEntity<MultiValueMap<String, String>> request1 = new HttpEntity<MultiValueMap<String, String>>(map, headers);
mcResponse response = restTemplate.postForObject(request, request1 , mcResponse.class );
return response;
}
However, I am getting the following error: 404 null.
Can you please help me? Thanks in advance
and here is the service class:
public ResponseEntity<mcResponse> getSentimentsMc(mcSentimentRequestDTO sentimentRequestDTO){
ResponseEntity<mcResponse> dto = null;
try {
dto = sentimentConverter.getTheSentiments(mcsParser.parseTheSentiments(sentimentRequestDTO.getText(),
Languages.ENGLISH, sentimentRequestDTO.getKey()));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return dto;
}
Looks like variable request should be
String request = "http://localhost:8080/something";
Also if controller class has prefix, this prefix also should be in request.
I mean if your class looks like this
#RestController
#RequestMapping("/myApi")
public class CertificateController {
....
#RequestMapping(value = "/something", method = RequestMethod.POST)
public ResponseEntity<mcResponse>getTheSentiments( mcSentimentRequestDTO sentimentRequestDTO){
return sentimentParserService.getSentimentsMc(sentimentRequestDTO);
}
Then request should be
String request = "http://localhost:8080/myApi/something";
It sounds like the controller isn't getting included in the spring context. If you just have an app annotated with #SpringBootApplication, then make sure that your controller is in a package that is the same as or lower than your annotated application.
To check the controller is being picked up you can add the following logging options to your application.properties
logging.level.org.springframework.beans=debug
logging.level.org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping=trace
When your server starts up you should see something like the following in the log
1. To show the controller is in the spring-context
DefaultListableBeanFactory : Creating shared instance of singleton bean 'sentimentParserController'
2. To show the mapping for the /api/something url
RequestMappingHandlerMapping : Mapped 1 handler method(s) for class SentimentParserController: {public org.springframework.http.ResponseEntity SentimentParserController.getTheSentiments(mcSentimentRequestDTO)={[/api/something],methods=[POST]}}
If you see both of these, then what you say you're doing should work. Just make sure you are sending the request to /api/something and the server is running on port 8080.

Internationalization Support for backend Messages in Spring Application

I am trying to implement internationalization in my application. I already went through many blogs & tutorials which explain how we can implement it using different libraries.
The one I am planning to use is I18N with spring.
My application's structure is something like this :-
My application's front end (based on Angular2) consumes Rest APIs that are exposed from the backend.
I am using Spring Rest for implementing the Rest APIs. For every API call I am preparing & sending appropriate messages to UI.
Now by default messages are in English but now I want to add internationalization support to it. How can I do it ?
Below is the example of one of the Rest API that I am exposing and the way I'm sending the messages :-
#CrossOrigin(methods = RequestMethod.POST)
#PostMapping(value = "/user/resetUserAccount", produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody ResponseEntity<String> resetUserAccount(#RequestBody InputObj inputObj) {
boolean isUserAccountReset = userService.resetUserAccount(inputObj);
if (isUserAccountReset) {
return new ResponseEntity<String>(successResponse("User Account Reset Successful").toString(), HttpStatus.OK);
}
return new ResponseEntity<String>(failureResponse("Failed to Reset User Account").toString(), HttpStatus.CONFLICT);
}
I have written 2 helper methods given below that prepare the response messages :-
private JSONObject successResponse(String apiMessage) {
JSONObject success = new JSONObject();
success.put("reponse", "success");
success.put("message", apiMessage);
return success;
}
private JSONObject failureResponse(String apiMessage) {
JSONObject failure= new JSONObject();
success.put("reponse", "failure");
success.put("message", apiMessage);
return failure;
}
Add the following to the configuration class
#Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver();
slr.setDefaultLocale(Locale.US); // Set default Locale as US
return slr;
}
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasenames("i18n/messages"); // name of the resource bundle
source.setUseCodeAsDefaultMessage(true);
return source;
}
Create a new directory named i18n inside resources directory and put your messages.properties and the other internationalized property files like messages_ru.properties, messages_fr.properties etc inside it. Create message key and values like below:
messages.properties
msg.success=User Account Reset Successful
msg.failure=Failed to Reset User Account
Now inject the MessageSource Bean where you want to internationalize the message, i.e. your controller and then accept the Locale from headers in controller method and get messages from properties files like below:
#Autowired
private MessageSource messageSource;
#CrossOrigin(methods = RequestMethod.POST)
#PostMapping(value = "/user/resetUserAccount", produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody ResponseEntity<String> resetUserAccount(#RequestHeader("Accept-Language") Locale locale, #RequestBody InputObj inputObj) {
boolean isUserAccountReset = userService.resetUserAccount(inputObj);
if (isUserAccountReset) {
return new ResponseEntity<String>(successResponse(messageSource.getMessage("msg.success",null,locale)).toString(), HttpStatus.OK);
}
return new ResponseEntity<String>(failureResponse(messageSource.getMessage("msg.failure",null,locale)).toString(), HttpStatus.CONFLICT);
}

Springfox Swagger adding response status 200 to POST and PUT

I am using springfox-swagger2 version 2.6.1, and it is inserting HTTP 200 response messages for PUT and POST operations automatically, despite my attempts to configure it not to do so (I do not use response status 200 for POST or PUT, but 201 and 204, respectively); see below screenshot:
I have seen answers to similar questions where the authors suggest adding a #ResponseStatus annotation to your controller to "fix" it, but this becomes inflexible and goes against Spring's own documentation regarding the use of ResponseEntity vs #ResponseStatus for rest APIs. Examples:
How to change the response status code for successful operation in Swagger?
and
https://github.com/springfox/springfox/issues/908
Is there any other way to force Springfox Swagger not to add this 200 OK status code?
My Docket configuration:
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.select().
apis(RequestHandlerSelectors.any()).
paths(paths()).
build()
.pathMapping("/")
.apiInfo(apiInfo())
.genericModelSubstitutes(ResponseEntity.class)
.alternateTypeRules(newRule(
typeResolver.resolve(DeferredResult.class, typeResolver.resolve(ResponseEntity.class, WildcardType.class)),
typeResolver.resolve(WildcardType.class)
));
...and the actual API endpoint declaration:
#RequestMapping(method = RequestMethod.POST, produces = "application/json")
#ApiOperation(value = "Create a new enrolment", code = 201)
#ApiResponses(value = {
#ApiResponse(code = 201, message = "New enrolment created",
responseHeaders = #ResponseHeader(name = "Location", description = "The resulting URI of the newly-created enrolment", response = String.class))})
#ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<Void> saveNewEnrolment(#ApiParam(value = "Enrolment to save", required = true) #RequestBody final Enrolment enrolment) {
// implementation code removed; "location" header is created and returned
return ResponseEntity.created(location).build();
}
Try adding #ResponseStatus(HttpStatus.CREATED) or #ResponseStatus(HttpStatus.NO_CONTENT) annotation. Taken from here
remove the
produces = "application/json"
part from the #RequestMapping annotation since your response is of type Void.class

Categories