A bit late for the party, but since SpringFox relies on Spring beans for building the documentation, we can easily manipulate it. Hope this can help someone!
Register it as a bean
@Primary
@Bean
public ApiListingScanner addExtraOperations(ApiDescriptionReader apiDescriptionReader, ApiModelReader apiModelReader, DocumentationPluginsManager pluginsManager)
{
return new FormLoginOperations(apiDescriptionReader, apiModelReader, pluginsManager);
}
The class used to add any operation manually:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import com.fasterxml.classmate.TypeResolver;
import com.google.common.collect.Multimap;
import springfox.documentation.builders.ApiListingBuilder;
import springfox.documentation.builders.OperationBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiDescription;
import springfox.documentation.service.ApiListing;
import springfox.documentation.service.Operation;
import springfox.documentation.spring.web.plugins.DocumentationPluginsManager;
import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator;
import springfox.documentation.spring.web.scanners.ApiDescriptionReader;
import springfox.documentation.spring.web.scanners.ApiListingScanner;
import springfox.documentation.spring.web.scanners.ApiListingScanningContext;
import springfox.documentation.spring.web.scanners.ApiModelReader;
public class FormLoginOperations extends ApiListingScanner
{
@Autowired
private TypeResolver typeResolver;
@Autowired
public FormLoginOperations(ApiDescriptionReader apiDescriptionReader, ApiModelReader apiModelReader, DocumentationPluginsManager pluginsManager)
{
super(apiDescriptionReader, apiModelReader, pluginsManager);
}
@Override
public Multimap<String, ApiListing> scan(ApiListingScanningContext context)
{
final Multimap<String, ApiListing> def = super.scan(context);
final List<ApiDescription> apis = new LinkedList<>();
final List<Operation> operations = new ArrayList<>();
operations.add(new OperationBuilder(new CachingOperationNameGenerator())
.method(HttpMethod.POST)
.uniqueId("login")
.parameters(Arrays.asList(new ParameterBuilder()
.name("username")
.description("The username")
.parameterType("query")
.type(typeResolver.resolve(String.class))
.modelRef(new ModelRef("string"))
.build(),
new ParameterBuilder()
.name("password")
.description("The password")
.parameterType("query")
.type(typeResolver.resolve(String.class))
.modelRef(new ModelRef("string"))
.build()))
.summary("Log in") //
.notes("Here you can log in")
.build());
apis.add(new ApiDescription("/api/login/", "Authentication documentation", operations, false));
def.put("authentication", new ApiListingBuilder(context.getDocumentationContext().getApiDescriptionOrdering())
.apis(apis)
.description("Custom authentication")
.build());
return def;
}
}
Rendering Swagger json:
"/api/login/" : {
"post" : {
"summary" : "Log in",
"description" : "Here you can log in",
"operationId" : "loginUsingPOST",
"parameters" : [ {
"name" : "username",
"in" : "query",
"description" : "The username",
"required" : false,
"type" : "string"
}, {
"name" : "password",
"in" : "query",
"description" : "The password",
"required" : false,
"type" : "string"
} ]
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…