Swagger: SpringFox to Springdoc — How to migrate
When we first incorporated Swagger into the CMPSC 156 code bases, we used a package called SpringFox. However, it came to pass that SpringFox was no longer being supported, and when a security vulnerability in SpringFox was discovered, it became necessary to migrate to SpringDoc 1.7.0.
Note that the most current version of SpringDoc as of August 2023 was Springdoc 2.1.0, but that version only supports Spring Boot 3.x, and we are still currently using Spring Boot 2.x, so we are using Springdoc 1.7.0 which can be found on GitHub here.
Note that the javadoc links here for the Springdoc annotations come from the 2.1.0 version; I was unable to find javadoc for the 1.7.0 version online. However, my impression is that the annotations referred to here are largely unchanged between 1.7.0 and 2.1.0.
This page describes the steps to take when migrating a CMPSC 156 code base from SpringFox to SpringDoc.
This page may also be helpful:
Here, also are some example PRs for this process:
- https://github.com/ucsb-cs156/proj-happycows/pull/60
- https://github.com/ucsb-cs156/proj-gauchoride/pull/53
Step 1: Replace @Api
with @Tag
in Controllers
Under SpringFox, controllers use the @Api
annotation (javadoc). This annotation is found at the top of each controller class.
import io.swagger.annotations.Api;
...
@Api(description = "Commons")
Under SpringDoc, @Api
is replaced with @Tag
(javadoc), like this:
import io.swagger.v3.oas.annotations.tags.Tag;
...
@Tag(name = "Restaurants")
So the two search and replaces needed are:
Find | Replace |
---|---|
@Api(description | @Tag(name |
import io.swagger.annotations.Api; | import io.swagger.v3.oas.annotations.tags.Tag; |
Be sure afterwards to look for any other instances of @Api
that your search/replace may have missed (for example @Api(
that might omit description
or have a space between the (
and the d
, etc.)
Step 2: Replace @ApiOperation
with @Operation
Under SpringFox, controller methods that provide an endpoint use the @ApiOperation
annotation (javadoc).
import io.swagger.annotations.ApiOperation;
...
@ApiOperation(value = "Get a list of all commons")
Under SpringDoc, @ApiOperation
is replaced with @Operation
(javadoc), like this:
import io.swagger.v3.oas.annotations.Operation;
...
@Operation(summary = "Restaurants")
So the two search and replaces needed are:
Find | Replace |
---|---|
@ApiOperation(value | @Operation(summary |
import io.swagger.annotations.ApiOperation; | import io.swagger.v3.oas.annotations.Operation; |
Be sure afterwards to look for any other instances of @ApiOperation(
that your search/replace may have missed.
Step 3: Replace @ApiParam
with @Parameter
Under SpringFox, parameters are annotated with @ApiParam
(javadoc).
import io.swagger.annotations.ApiParam;
...
@ApiParam("id") @RequestParam long id)
Under SpringDoc, @ApiParam
is replaced with @Parameter
(javadoc), like this:
import io.swagger.v3.oas.annotations.tags.Parameter;
...
@Parameter(name = "id") @RequestParam Long id,
So the two search and replaces needed are:
Find | Replace |
---|---|
@ApiParam( | @Parameter(name= |
import io.swagger.annotations.ApiParam; | import io.swagger.v3.oas.annotations.Parameter; |
Be sure afterwards to look for any other instances of @ApiParam(
that your search/replace may have missed.
After doing step 3, if you have errors, it may be because of additional parameters to @ApiParam
that need to be changed.
Consult the documentation for @Parameter
here to see what parameters are supported.
The most commonly used ones are these; typically, you’ll need to figure out how to fit any old parameters from @ApiParam
into one of the following, or else delete it:
Parameter | type | explanation |
---|---|---|
name | String | name of the parameter |
allowEmptyValue | boolean | whether or not the parameter allows empty values |
example | String | an example value for the parameter |
description | String | description of the purpose of the parameter |
Step 4: Other search/replaces
The search/replaces in Steps 1,2,3 are likely enough to pick up most or all of the SpringFox annotations that we used, but you may want to look for these as well; you may need to look at the javadoc for each to find the details of any parameter names you need to adjust:
Here are the ones you already did in steps 1-3:
SpringFox | SpringDoc |
---|---|
@Api | @Tag |
@ApiOperation(value = "foo", notes = "bar") | `@Operation(summary = “foo”, description = “bar”) |
@ApiParam | `@Parameter |
Here are the others you could run into. The headers to the table take you to the javadoc for each.
Rather than searching for each, it may be easier to just skip this step for now, and come back to it if you find you have compilation errors at a later stage, since the use of any of these in our codebase is rare.
SpringFox | SpringDoc |
---|---|
@ApiIgnore | @Parameter(hidden = true) or @Operation(hidden = true) or @Hidden |
@ApiImplicitParam | @Parameter |
@ApiImplicitParams | @Parameters |
@ApiModel | @Schema |
@ApiModelProperty(hidden = true) | @Schema(accessMode = READ_ONLY) |
@ApiModelProperty | @Schema |
@ApiResponse(code = 404, message = "foo") | @ApiResponse(responseCode = "404", description = "foo") |
You can find examples of changing @ApiModelProperty
to @Schema
in this PR that Colin worked on:
The import is:
import io.swagger.v3.oas.annotations.media.Schema;
Step 4: Change pom.xml
Remove references to springfox from the pom.xml
such as these:
<!-- https://www.baeldung.com/swagger-2-documentation-for-spring-rest-a
pi -->
<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>
Replace with this:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.7.0</version>
</dependency>
Step 5: Replace SpringFoxConfig.java
(or equivalent) with OpenApiConfig.java
Look for a file with the name SpringFoxConfig.java
or something similar. It should have content such as this:
@Configuration
public class SpringFoxConfig {
@Bean
public Docket api() {
...
Remove this file entirely. Instead, under the config
directory, create a file called OpenAPIConfig.java
with the following contents (adjusted as appropriate for your project). The HTML under description
will be placed at the top of your Swagger page.
In this example, I put links to the home page of the application, and a link to the H2-Console; you may put whatever links or information you think will be useful to developers working with the Swagger page. Note that the class
definition is deliberately empty; the OpenAPIDefinition
annotation is doing all of the work here.
Also be sure to replace the package
name with one appropriate to your application.
package edu.ucsb.cs156.yourappname.config;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.servers.Server;
@OpenAPIDefinition(
info = @Info(
title = "Name of Your Project goes here",
description = """
<p><a href='/'>Home Page</a></p>
<p><a href='/h2-console'>H2 Console (only on localhost)</a></p>
"""
),
servers = @Server(url = "/")
)
class OpenAPIConfig {}
Step 6: Update application.properties
In src/main/resources/application.properties
, locate the application properties associated with swagger and springfox:
springfox.documentation.swagger.v2.path=/api/docs
Remove the lines that start with springfox
such as the one above.
Add these lines:
management.endpoints.web.exposure.include=mappings
springdoc.swagger-ui.tryItOutEnabled=true
springdoc.swagger-ui.csrf.enabled=true
This article explains the last line:
Step 7: Test it
Now, you should be able to fire up the application on localhost and test your swagger page.
mvn spring-boot:run
in first windowcd frontend; npm start
in the second window
In the second window, as a reminder, you may need to first type nvm use version-number and npm install, depending on how your dev environment is set up.
If you have compilation errors, review the steps above. If not, then look for the Swagger page.
Note that the page may be at either of these links; you may need to try both to get things to work properly.
http://localhost:8080/swagger-ui
http://localhost:8080/swagger-ui/index.html
Note also that many swagger endpoints require authentication, which is why we include a link to the home page on our swagger header, and we suggest firing up the frontend (where you can authenticate with OAuth prior to trying any given swagger endpoint.)