Spring Boot | Using SWAGGER at maximum — Grouping/Definition/Tag
Paladuta Stefan
Posted on July 1, 2023
The main article that bundles all together and redirect to different features that you can implement in swagger UI is present here: https://medium.com/@stefan.paladuta17/spring-boot-using-swagger-at-maximum-9828ae9fb9d0
In this article I am going to show how grouping/definitions/tags can be achieved in swagger UI.
Why should you bother to implement grouping in your application ?
- Maybe you have an application that exposes a ton of endpoints and that means you may have developers that want to group them logically.
- Maybe you have an application that has a ton of controllers that together, bundles the everything too tight (from an SWAGGER UI point of view) and separation should be applied.
- Maybe you have an application that is presented as a monolith and exposes a ton of web services for different groups/teams. In this case you may want to divide them based for who they are exposed so that the UI generate via swagger won’t be huge and confusing but instead be directly focused on specific group of consumers.
- Categorizing apis.
How to do grouping ?
1 — Using GROUPS
We create first the Docket’s. In my case I create 2 docket bean’s that will be for 2 groups (address and accounting):
package ro.stefan.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
@Configuration
public class SpringFoxConfig {
@Bean
public Docket api1() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("address")
.select()
.apis(RequestHandlerSelectors.basePackage("ro.stefan.external.apis.address"))
.paths(PathSelectors.any())
.build();
}
@Bean
public Docket api2() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("accounting")
.select()
.apis(RequestHandlerSelectors.basePackage("ro.stefan.external.apis.accounting"))
.paths(PathSelectors.any())
.build();
}
}
the layout of the project is the following (also can be seen directly via my github repo. attached at the end of the article):
in this layout we have 2 basic controllers ( AccountingController and AddressController ) with just methods that return null that are put there just for the POC (Proof Of Concept). And the result:
we can see that the generate UI swagger has in the Select definition comboBox our 2 groups.
2 — Using TAGS
Using Tags it’s more interesting, here we don’t have anymore definitions (the combo box) but we define a proper grouping of endpoint. First I start with sharing the Docket code:
package ro.stefan.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Tag;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
@Configuration
public class SpringFoxConfig {
@Bean
public Docket api3() {
// here tags is optional, it just adds a description in the UI
// by default description is class name, so if you use same tag using
// `@Api` on different classes it will pick one of the class name as
// description, so better define your own description for them
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.tags(new Tag("security", "security related"),
new Tag("loan", "loan related"))
.select()
.apis(RequestHandlerSelectors.basePackage("ro.stefan.external.apis"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Openapi OAS3 with springfox ")
.description("Code first approach")
.version("1.0.0")
.contact(new Contact("Stefan", "https://test.com", "test@test.com"))
.build();
}
}
the layout of the project is the following:
@RestController
public class AccountingController {
@GetMapping("/accounts")
public List<String> getAccounts(){
return null;
}
}
/* ----------------------- */
@RestController
public class AddressController {
@GetMapping("/addresses")
public List<String> getAddresses(){
return null;
}
}
/* ----------------------- */
@RestController
@Api(tags = "loan")
public class LoanController {
@GetMapping("/loan")
public String getLoanDetails() {
return null;
}
}
/* ----------------------- */
@RestController
@Api(tags = "security")
public class SecurityController {
@GetMapping("/user")
public String getUser() {
return null;
}
}
in this layout we have 4 basic controllers with just a method that return null but put there just for the POC (Proof Of Concept) and the result
Interesting, so by putting on 2 controllers the necessary annotation @Tag we just unlocked the power to change also the name of the group and the description.
We can see that 2 controllers that aren’t annotated with the @Tag are auto-generated their names (accounting-controller and address-controller) and the 2 controllers that we annotated with @Tag are named and descripted as we written in the Docket code.
You can have operations under multiple tags, but not tags under tags.
Conclusion: The concept of grouping API’s is not something specific to java here I encourage you to follow if you want to see the same principle applied for .NET Core, C#: http://www.mattruma.com/adventures-in-apis-grouping-controllers-in-swagger/
If you want my code you can find it here: https://github.com/Kanames/SpringBoot-SwaggerExamples
If you liked the article please take a minute to offer me a clap 👏 or even buy me a coffee https://www.buymeacoffee.com/stefansplace (;
References:
https://medium.com/p/2b25eb39a0cb
Posted on July 1, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.