Swagger: How to use password format (Parameter annotation) for a String field ? Currently it won't allow me to submit the form with a value - spring-boot

I have a Spring Boot app (2.7.0) with spring docs (1.6.9)
Endpoint defined as follows:
#PostMapping(value = "/upload", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
#Operation(summary = "blah blah blah")
public ResponseEntity<UploadSummary> uploadData(
#RequestParam("file") final MultipartFile csvFile,
#Parameter(schema = #Schema(type = "string", format = "password"))
#RequestParam("password") final String password,
#RequestParam(name = "dryRun", required = false, defaultValue = "true") final boolean dryRun) {
I want to have the password input field on the Swagger interface mask the input. The only change I have made above is to include a single #Parameter annotation, nothing else.
The Swagger interface does not appear to like this single Parameter annotation at all, regardless of format. If I input a value in the password field, it is always highlighted with a red border and I cannot execute.
I tried upgrading to 1.6.12 but still doesn't work.
Perhaps other annotations or code needs to be setup before these Parameter annotations and Schema types work ?

Related

How to use #RequestParam Map<String,String> properly in Swagger UI?

I'm trying to use springfox-swagger-ui for this request:
#GetMapping(value = "")
public String Hello( #RequestParam Map<String, String> params )
When I open Swagger UI and try the request, it shows the parameters like this:
and the request query string will be like:
?params%5BadditionalProp1%5D=string&params%5BadditionalProp2%5D=string&params%5BadditionalProp3%5D=string
I don't want the word "params" to be included in the query string, I want the parameters be like ?additionalProp1=string ....
How can I achieve this?
Add the following #Parameter annotation to your parameter (line breaks added for readability). The style and explode attributes specify that the map parameter should be serialized as ?key1=value1&key2=value2&... without including the parameter name ("params").
#GetMapping(value = "")
public String Hello(
#Parameter(name = "params",
in = ParameterIn.QUERY,
required = true,
schema = #Schema(type = "object", additionalProperties = true),
style = ParameterStyle.FORM,
explode = Explode.TRUE)
#RequestParam Map<String, String> params
)

Wrapper type Path variable won't accept null value - Spring Boot

This is our Controller
#GetMapping(path = "/getUsersForHierarchy/{entity}/{hierId}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<UserInfo>> getUsersForHierarchy(#PathVariable(name = "entity", required = true) int entity,
#PathVariable(name = "hierId", required = true) Integer hierId) {
..................
..................
}
We are expecting two Path variables, one is of int type (entity) and the other is Integer type (hierId). hierId can be null or any numeric value and thats why its kept as Wrapper. But its gives error while firing the request like this
http://localhost:5010/v1/accountholder/userinfo/getUsersForHierarchy/5/null
Now a Wrapper is meant to accept null values, but we are getting error like this
Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: "null"
If we change Integer to String the call is getting inside the controller, but for further proceedings we need to use Integer.
We looked into this Spring MVC #Path variable with null value, and tried invoking the API with change in URL like this
http://localhost:5010/v1/accountholder/userinfo/getUsersForHierarchy/5/blaaa/null, but the error is still the same.
What should be done?
If you want it to be nullable you can achieve it with the following. First of all, if it's nullable the required property should be false. Also, considering required = true is the default, there's no need to specify it and if the name of the path variable matches the name of the corresponding variable you don't have to specify the name either.
#GetMapping(value = {
"/getUsersForHierarchy/{entity}/",
"/getUsersForHierarchy/{entity}/{hierId}"
},
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<UserInfo>> getUsersForHierarchy(
#PathVariable int entity,
#PathVariable(required = false) Integer hierId) {
}
Considering I don't like to deliberately allow a null value into the application, another nice to have could be having the hierId required with type Optional, so the following will give you a Optional.empty when just /getUsersForHierarchy/123/ is invoked and hierId is null. Otherwise it will populate the optional when hierId is provided invoking /getUsersForHierarchy/123/321:
#GetMapping(value = {
"/getUsersForHierarchy/{entity}/",
"/getUsersForHierarchy/{entity}/{hierId}"
},
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<UserInfo>> getUsersForHierarchy(
#PathVariable int entity,
#PathVariable Optional<Integer> hierId) {
}

How to collect all fields annotated with #RequestParam into one object

I would like to gather all of my query parameters into a pojo and perform additional validation of the fields.
I have read that I can simply create an object and spring-boot will automatically set those request parameters on it.
#GetMaping
public ResponseEntity<?> listEntities(#RequestParam(value = "page-number", defaultValue = "0") #Min(0) Integer pageNumber,
#RequestParam(value = "page-size", defaultValue = "100") #Min(1) Integer pageSize ... )
I am thinking to create a class called RequestParamsDTO, where I'd have my query params responsible for the pagination.
But in order to have those fields set on the RequestParamsDTO, I'd have to match the name of the request param with the field name. But it won't be a valid variable name: page-size.
There must be some workaround, similar to #RequestParam's value attribute, that would set given request param on my field in the DTO.
Please advise.
Someone already purposed this feature before such that you can do the following .But unfortunately it is declined due to inactivity response :
public class RequestParamsDTO{
#RequestParam(value="page-number",defaultValue="0")
#Min(0)
private Integer pageNumber;
#RequestParam(value = "page-size", defaultValue = "100")
#Min(1)
Integer pageSize
}
The most similar things that you can do is using its #ModelAttribute which will resolve the parameter in the following orders:
From the model if already added by using Model.
From the HTTP session by using #SessionAttributes.
From a URI path variable passed through a Converter (see the next example).
From the invocation of a default constructor.
From the invocation of a “primary constructor” with arguments that match to Servlet request parameters. Argument names are determined through JavaBeans #ConstructorProperties or through runtime-retained parameter names in the bytecode.
That means the RequestParamsDTO cannot not have any default constructor (constructor that is without arguments) .It should have a "primary constructor" which you can use #ConstructorProperties to define which request parameters are mapped to the constructor arguments :
public class RequestParamsDTO{
#Min(0)
Integer pageNumber;
#Min(1)
Integer pageSize;
#ConstructorProperties({"page-number","page-size"})
public RequestParamsDTO(Integer pageNumber, Integer pageSize) {
this.pageNumber = pageNumber != null ? pageNumber : 0;
this.pageSize = pageSize != null ? pageSize : 100;
}
}
And the controller method becomes:
#GetMaping
public ResponseEntity<?> listEntities(#Valid RequestParamsDTO request){
}
Notes:
There is no equivalent annotation for #RequestParam 's defaultValue,so need to implement in the constructor manually.
If the controller method argument does not match the values in this , it will resolved as #ModelAttribute even though #ModelAttribute is not annotated on it explicitly.
To be honest this seems like a lot of effort for a functionality that exists already in spring-boot. You can either extend your repositories from PagingAndSortingRepository and have pagination added whenever you call a collection resource.
Or you can write a custom query method (or overwrite an existing one) and add this:
Page<Person> findByFirstname(String firstname, Pageable pageable);
This way spring boot will automatically add all those parameters you want to the Request.

Want to document optional JSON parameters in Swagger

I have an API that I'm trying to document using Swagger. My API takes a POJO as input via JSON in the RequestBody, and returns, likewise, a POJO as JSON in the ResponseBody. Some of the fields in my JSON object are nullable, and others are required. I would like my Swagger documentation to reflect which fields are nullable and which are required. Is there a way to do this simply, without creating a Swagger config file which would likely be longer than manually documenting the API in a text editor?
As a concrete example, let's say I have a POJO that looks like this:
public class pojo {
private String val1;
private String val2;
private String val3;
//getters, setters, constructors, etc.
}
Let's say I wanted my Swagger documentation to tell the reader: "On request, do not send val1 (e.g. this API is a database insert and val1 corresponds to the PK of the table which is supposed to be auto-generated), val2 is optional, and val3 is required". How do I do this?
As a related question, how can I do something similar for the response body? Like, using the POJO above, how can I say "on response, you should expect val1 to be empty, val2 might have a value or might be null, and val3 should have a value, assuming the service was successful"?
In order to document optional parameters within your POJO object it is possible to use the #ApiModelProperty attribute, for example:
public class pojo {
#ApiModelProperty(value = "This parameter will be ignored", required = false)
private String val1;
#ApiModelProperty(value = "This parameter is optional", required = false)
private String val2;
#ApiModelProperty(required = true)
private String val3;
//getters, setters, constructors, etc.
}
Swagger will take these annotations into account and it should be reflected in the documentation:
And in yaml API documentation:
pojo:
type: object
required:
- val3
properties:
val1:
type: string
description: This parameter will be ignored
val2:
type: string
description: This parameter is optional
val3:
type: string

obscuring url strings in spring mvc

How do I obscure the values of fields used in url strings in a spring mvc web app?
For example, if I want to send the record with recordID=1 into the view, I give the user a hyperlink with the following url:
https://myapp.com/urlpattern?recordID=1
As you can see, this not only exposes the recordID=1, it also tempts a malicious user to start typing other numbers to mine other records such as recordID=5 or recordID=9.
Does the spring framework or spring security have a built-in way of encrypting url strings? Or do I need to change the id values in the underlying database using hibernate?
The controller code for the above url pattern is:
#RequestMapping(value = "/urlpattern", method = RequestMethod.GET)
public String processUrlPattern(#RequestParam("recordID") String recordId,
HttpServletRequest request, BindingResult result, Map<String, Object> model) {
Long recId = Long.valueOf(recordId).longValue();
RecordObject sel_record = this.appService.findRecordById(recId);
model.put("sel_record", sel_record);
return "foldername/jspname";
}
Note that all entities in the app inherit from the same BaseEntity whose id-generating code is as follows:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#DiscriminatorFormula("(CASE WHEN dtype IS NULL THEN 'BaseEntity' ELSE dtype END)")
#org.hibernate.annotations.DiscriminatorOptions(force=true)
public abstract class BaseEntity {
#Transient
private String dtype = this.getClass().getSimpleName();
#Id
#GeneratedValue(strategy=GenerationType.TABLE, generator="TBL_GEN")
#TableGenerator(
name="TBL_GEN",
table="GENERATOR_TABLE",
pkColumnName = "mykey",
valueColumnName = "hi",
pkColumnValue="id",
allocationSize=20
)
protected Integer id;
//other stuff
}
NOTE: All the users are authenticated/authorized using Spring security. However, the data is very sensitive, and it is important that no one be able to manipulate url strings.
Use HDIV, it does this out of the box:
http://hdiv.org/hdiv-documentation-single/doc.html
"A6 (Sensitive data exposure) : HDIV offers a confidentially property to all data generated at sever side. That is to say, HDIV replace original parameter values generated at server side by relative values (0,1,2,4, etc.) that avoid exposing critical data to the client side."

Resources