Swagger UI put my every endpoint in the "default" group
Here's the JSON it gets (don't ask how I got it). Notice there are no tags (I also tried empty lists instead of nulls which are not serialized by Jackson)
{
"openapi": "3.0.3",
"info": {
"title": "Api Documentation",
"description": "Api Documentation",
"termsOfService": "urn:tos",
"contact": { },
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0"
},
"version": "1.0"
},
"servers": [
{
"url": "https://localhost:8080",
"description": "Api-Gateway-V2"
}
],
"paths": {
"/api/v1/hello-world": {
"get": {
"summary": "getHelloWorld",
"operationId": "getHelloWorldUsingGET",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/SuccessMessage",
"exampleSetFlag": false
},
"exampleSetFlag": false
}
}
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
}
}
},
"/api/v1/joy": {
"get": {
"summary": "getMessageOfJoy",
"operationId": "getMessageOfJoyUsingGET",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/SuccessMessage",
"exampleSetFlag": false
},
"exampleSetFlag": false
}
}
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
}
}
},
"/api/v1/error": {
"get": {
"summary": "error",
"operationId": "errorUsingGET",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/FailureMessage",
"exampleSetFlag": false
},
"exampleSetFlag": false
}
}
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
}
},
"put": {
"summary": "error",
"operationId": "errorUsingPUT",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/FailureMessage",
"exampleSetFlag": false
},
"exampleSetFlag": false
}
}
},
"201": {
"description": "Created"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
}
},
"post": {
"summary": "error",
"operationId": "errorUsingPOST",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/FailureMessage",
"exampleSetFlag": false
},
"exampleSetFlag": false
}
}
},
"201": {
"description": "Created"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
}
},
"delete": {
"summary": "error",
"operationId": "errorUsingDELETE",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/FailureMessage",
"exampleSetFlag": false
},
"exampleSetFlag": false
}
}
},
"204": {
"description": "No Content"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
}
}
},
"options": {
"summary": "error",
"operationId": "errorUsingOPTIONS",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/FailureMessage",
"exampleSetFlag": false
},
"exampleSetFlag": false
}
}
},
"204": {
"description": "No Content"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
}
}
},
"head": {
"summary": "error",
"operationId": "errorUsingHEAD",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/FailureMessage",
"exampleSetFlag": false
},
"exampleSetFlag": false
}
}
},
"204": {
"description": "No Content"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
}
}
},
"patch": {
"summary": "error",
"operationId": "errorUsingPATCH",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/FailureMessage",
"exampleSetFlag": false
},
"exampleSetFlag": false
}
}
},
"204": {
"description": "No Content"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
}
}
},
"trace": {
"summary": "error",
"operationId": "errorUsingTRACE",
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/FailureMessage",
"exampleSetFlag": false
},
"exampleSetFlag": false
}
}
},
"204": {
"description": "No Content"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
}
}
}
}
},
"components": {
"schemas": {
"FailureMessage": {
"title": "FailureMessage",
"type": "object",
"properties": {
"message": {
"type": "string",
"exampleSetFlag": false,
"types": [
"string"
]
},
"method": {
"type": "string",
"exampleSetFlag": false,
"types": [
"string"
],
"enum": [
"DELETE",
"GET",
"HEAD",
"OPTIONS",
"PATCH",
"POST",
"PUT",
"TRACE"
]
},
"request_path": {
"type": "string",
"exampleSetFlag": false,
"types": [
"string"
]
}
},
"exampleSetFlag": false,
"types": [
"object"
]
},
"SuccessMessage": {
"title": "SuccessMessage",
"type": "object",
"properties": {
"message": {
"type": "string",
"exampleSetFlag": false,
"types": [
"string"
]
}
},
"exampleSetFlag": false,
"types": [
"object"
]
}
},
"extensions": { }
}
}
Result (it's UI hence the screenshot):
My Swagger dependencies are:
<!-- API Gateway -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
<version>2.0.4</version>
</dependency>
Gateway: Java 17, Boot 3
<!-- microservice -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
Microservice: Java 17, Boot 2
I obviously want it to group by controllers, as it usually does
Why is Swagger doing it?
Here's what I found
Swagger UI groups endpoints by tags
If no custom tags are added (with @Tag
), Swagger will automatically create a tag for your controller class that matches that class's name (e.g. example-controller
). Class-level tags (including default ones Swagger creates) will propagate to every endpoint declared within that controller class
If a controller class or at least one of its methods has its own tag, Swagger will not create a default tag for that class. Even if you then manually remove your custom tag from an OpenApi
object before serving it to Swagger UI, you still won't have that default tag. What that means is that those tag-less endpoints will be grouped into the "default" group