5

I build a REST interface using Spring Boot framework. Then, I use Swagger version 2.9.2 to generate the documentation. As you can see from the photo below, Swagger automatically detects a lot of models.

Models

However, most of them are redundant. Among them, only the ResponseMessage is necessary, the rest are just standard Java class.

So, my question is: how can I tell Swagger which models to expose?

Here are my Swagger configuration and code snippet of my controller.

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage("my.package"))
            .paths(PathSelectors.any())
            .build()
            .apiInfo(API_INFO)
            .useDefaultResponseMessages(false);
}

Controller:

@PostMapping(value = "/import", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> importData(HttpServletRequest request) {

    // processing...

    return ResponseEntity.created(uri)
        .body(new ResponseMessage(HttpStatus.CREATED, "Your data is being processed"));
}
Triet Doan
  • 11,455
  • 8
  • 36
  • 69
  • Not exactly answer to the question but I could selectively remove models using .ignoredParameterTypes() from Docket. I referenced answers from https://stackoverflow.com/questions/46651381/is-there-a-way-i-can-stop-springfox-swagger-from-scanning-the-model-classes?noredirect=1&lq=1 – TGLEE Apr 16 '21 at 10:46

5 Answers5

3

You can use :

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2).select()
            .apis(RequestHandlerSelectors.basePackage("com.package"))
            .paths(PathSelectors.regex("/api.*")).build().apiInfo(apiInfo())
            .ignoredParameterTypes(Timestamp.class);
}

This worked for me. After specifying the class name in ignoredParameterTypes, it was no longer present in swagger ui.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Alisha Raju
  • 726
  • 6
  • 12
0

You can use hidden attribute of @ApiModelProperty to hide any specific property of the model. There is no global setting for it.

Once you have base-package for swagger scan declared, swagger will generate definitions for all components in the package out of box for you. However, with correct use of set of swagger annotations, you can override/customize your swagger documentation.

Please follow these great tutorials (1, 2) to familiarize yourself with most useful annotations & usage.

@Api, @ApiOperation, @ApiResponses, @ApiParam, @ApiIgnore, @ApiModel, @ApiModelProperty etc

Amith Kumar
  • 4,400
  • 1
  • 21
  • 28
  • That's not my question. I want to hide the whole auto-detected models, not some properties of my model. – Triet Doan Mar 14 '19 at 21:27
  • Have you tried using the `@ApiOperation(value = "Some definition", response = MyModel.class)` with `response` attribute to direct to given model and not do the guess work ? I know that's not your question, but what you are asking, there is no global setting for that, you have to use annotations to customize your doc. – Amith Kumar Mar 14 '19 at 21:31
  • I did. But I want to know how to hide or prevent Swagger from automatically detecting some unnecessary classes, such as `File`, `InputStream`, as you can see on the screenshot. – Triet Doan Mar 15 '19 at 09:40
  • I need more information on your package structure, and then more piece of code showing swagger annotation on controller & model classes, to be able to assist. – Amith Kumar Mar 15 '19 at 15:55
  • Hi Triet, Were you able figure out answer to your question ?? – Hiten Rastogi Dec 27 '19 at 07:45
  • Sadly not yet :( – Triet Doan Apr 16 '21 at 10:22
0

Springfox Swagger2 acquire UI data through GET /v2/api-docs, which will mapping to springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation().So you can just create a bean to take place of 'ServiceModelToSwagger2Mapper':

@Primary
@Component
class CustomServiceModelToSwagger2Mapper : ServiceModelToSwagger2MapperImpl() {
    @Autowired
    private lateinit var modelMapper: ModelMapper
    @Autowired
    private lateinit var parameterMapper: ParameterMapper
    @Autowired
    private lateinit var securityMapper: SecurityMapper
    @Autowired
    private lateinit var licenseMapper: LicenseMapper
    @Autowired
    private lateinit var vendorExtensionsMapper: VendorExtensionsMapper

    override fun mapDocumentation(from: Documentation?): Swagger? {
        if (from == null) {
            return null
        }

        val swagger = Swagger()

        swagger.vendorExtensions = vendorExtensionsMapper.mapExtensions(from.vendorExtensions)
        swagger.schemes = mapSchemes(from.schemes)
        swagger.paths = mapApiListings(from.apiListings)
        swagger.host = from.host
// ➡➡➡➡➡➡➡➡➡➡➡➡➡➡➡➡ here
        swagger.definitions = this.modelsFromApiListings(from.apiListings)
        swagger.securityDefinitions = securityMapper.toSecuritySchemeDefinitions(from.resourceListing)
        val info = fromResourceListingInfo(from)
        if (info != null) {
            swagger.info = mapApiInfo(info)
        }
        swagger.basePath = from.basePath
        swagger.tags = tagSetToTagList(from.tags)
        val list2 = from.consumes
        if (list2 != null) {
            swagger.consumes = ArrayList(list2)
        } else {
            swagger.consumes = null
        }
        val list3 = from.produces
        if (list3 != null) {
            swagger.produces = ArrayList(list3)
        } else {
            swagger.produces = null
        }

        return swagger
    }

    private fun fromResourceListingInfo(documentation: Documentation?): ApiInfo? {
        if (documentation == null) {
            return null
        }
        val resourceListing = documentation.resourceListing ?: return null
        return resourceListing.info ?: return null
    }


    /**
     * @see ModelMapper
     */
    internal fun modelsFromApiListings(apiListings: Multimap<String, ApiListing>): Map<String, Model>? {
        val definitions = newTreeMap<String, springfox.documentation.schema.Model>()
        for (each in apiListings.values()) {
// ➡➡➡➡➡➡➡➡➡➡➡➡➡➡➡➡ here
            // definitions.putAll(each.models)
            definitions.putAll(each.models.filter {
                it.value.qualifiedType.startsWith("com.cpvsn")
                        && it.value.type.typeBindings.isEmpty    
            })
        }
        return modelMapper.mapModels(definitions)
    }
}
nanlan
  • 1
0

I was able to achieve this by adding genericModuleSubstitutes() in Docket().

Example:

.genericModelSubstitutes(ResponseEntity.class) would substitute ResponseEntity <MyModel> with MyModel.

Reference

4b0
  • 21,981
  • 30
  • 95
  • 142
0
@Bean
UiConfiguration uiConfig() {
    return UiConfigurationBuilder.builder()
            .defaultModelsExpandDepth(-1)
            .build();
}

This worked for me.