16

I'm having trouble getting this to work. I've started with a working SpringBoot (v2.2.2) app with a working @RestController. To get springdoc to work I've included the following dependency in my pom:

 <dependency>
  <groupId>org.springdoc</groupId>
  <artifactId>springdoc-openapi-ui</artifactId>
  <version>1.2.28</version>
</dependency>

I then built and started my service. I've then browsed to the api-docs endpoint and I get:

{"openapi":"3.0.1","info":{"title":"OpenAPI definition","version":"v0"},"servers":[{"url":"http://localhost:8081","description":"Generated server url"}],"paths":{},"components":{}}

Am I missing a step? I was assuming at runtime it would scan my code, find the @RestController, find the @RequestMapping methods and generate the api from that.

As a second attempt, I decided to annotate one of my methods with swagger @Operation annotations and still things don't get picked up.

Lastly, I tried specifying the package with my Controller manually using springdoc.packagesToScan and that didn't work either.

This feels like springdoc isn't seeing my Controller.. even though spring does.. it's perfectly active and it works..

Not sure what I'm missing..

here are my project dependencies:

[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.2.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:2.2.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:2.2.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.2.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.2.2.RELEASE:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] |  |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.12.1:compile
[INFO] |  |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.12.1:compile
[INFO] |  |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.29:compile
[INFO] |  |  +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.25:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-json:jar:2.2.2.RELEASE:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.10.1:compile
[INFO] |  |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.10.1:compile
[INFO] |  |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.10.1:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.10.1:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.10.1:compile
[INFO] |  |  \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.10.1:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.2.2.RELEASE:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.29:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:9.0.29:compile
[INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.29:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-validation:jar:2.2.2.RELEASE:compile
[INFO] |  |  +- jakarta.validation:jakarta.validation-api:jar:2.0.1:compile
[INFO] |  |  \- org.hibernate.validator:hibernate-validator:jar:6.0.18.Final:compile
[INFO] |  |     +- org.jboss.logging:jboss-logging:jar:3.4.1.Final:compile
[INFO] |  |     \- com.fasterxml:classmate:jar:1.5.1:compile
[INFO] |  +- org.springframework:spring-web:jar:5.2.2.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-beans:jar:5.2.2.RELEASE:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:5.2.2.RELEASE:compile
[INFO] |     +- org.springframework:spring-aop:jar:5.2.2.RELEASE:compile
[INFO] |     +- org.springframework:spring-context:jar:5.2.2.RELEASE:compile
[INFO] |     \- org.springframework:spring-expression:jar:5.2.2.RELEASE:compile
[INFO] +- com.google.guava:guava:jar:28.1-jre:compile
[INFO] |  +- com.google.guava:failureaccess:jar:1.0.1:compile
[INFO] |  +- com.google.guava:listenablefuture:jar:9999.0-empty-to-avoid-conflict-with-guava:compile
[INFO] |  +- com.google.code.findbugs:jsr305:jar:3.0.2:compile
[INFO] |  +- org.checkerframework:checker-qual:jar:2.8.1:compile
[INFO] |  +- com.google.errorprone:error_prone_annotations:jar:2.3.2:compile
[INFO] |  +- com.google.j2objc:j2objc-annotations:jar:1.3:compile
[INFO] |  \- org.codehaus.mojo:animal-sniffer-annotations:jar:1.18:compile
[INFO] +- org.apache.commons:commons-lang3:jar:3.9:compile
[INFO] +- org.springdoc:springdoc-openapi-ui:jar:1.2.28:compile
[INFO] |  +- org.springdoc:springdoc-openapi-webmvc-core:jar:1.2.28:compile
[INFO] |  |  \- org.springdoc:springdoc-openapi-common:jar:1.2.28:compile
[INFO] |  |     +- io.swagger.core.v3:swagger-models:jar:2.1.1:compile
[INFO] |  |     +- io.swagger.core.v3:swagger-annotations:jar:2.1.1:compile
[INFO] |  |     \- io.swagger.core.v3:swagger-integration:jar:2.1.1:compile
[INFO] |  |        \- io.swagger.core.v3:swagger-core:jar:2.1.1:compile
[INFO] |  |           +- javax.xml.bind:jaxb-api:jar:2.3.1:compile
[INFO] |  |           |  \- javax.activation:javax.activation-api:jar:1.2.0:compile
[INFO] |  |           +- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.10.1:compile
[INFO] |  |           \- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO] |  +- org.webjars:swagger-ui:jar:3.24.3:compile
[INFO] |  \- org.webjars:webjars-locator:jar:0.38:compile
[INFO] |     \- org.webjars:webjars-locator-core:jar:0.41:compile
[INFO] |        +- io.github.classgraph:classgraph:jar:4.8.44:compile
[INFO] |        \- org.webjars.npm:angular__http:jar:2.4.10:compile
[INFO] +- org.assertj:assertj-core:jar:3.14.0:test
[INFO] \- org.springframework.boot:spring-boot-starter-test:jar:2.2.2.RELEASE:test
[INFO]    +- org.springframework.boot:spring-boot-test:jar:2.2.2.RELEASE:test
[INFO]    +- org.springframework.boot:spring-boot-test-autoconfigure:jar:2.2.2.RELEASE:test
[INFO]    +- com.jayway.jsonpath:json-path:jar:2.4.0:test
[INFO]    |  +- net.minidev:json-smart:jar:2.3:test
[INFO]    |  |  \- net.minidev:accessors-smart:jar:1.2:test
[INFO]    |  |     \- org.ow2.asm:asm:jar:5.0.4:test
[INFO]    |  \- org.slf4j:slf4j-api:jar:1.7.29:compile
[INFO]    +- jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.2:test
[INFO]    |  \- jakarta.activation:jakarta.activation-api:jar:1.2.1:test
[INFO]    +- org.junit.jupiter:junit-jupiter:jar:5.5.2:test
[INFO]    |  +- org.junit.jupiter:junit-jupiter-api:jar:5.5.2:test
[INFO]    |  |  +- org.opentest4j:opentest4j:jar:1.2.0:test
[INFO]    |  |  \- org.junit.platform:junit-platform-commons:jar:1.5.2:test
[INFO]    |  +- org.junit.jupiter:junit-jupiter-params:jar:5.5.2:test
[INFO]    |  \- org.junit.jupiter:junit-jupiter-engine:jar:5.5.2:test
[INFO]    +- org.junit.vintage:junit-vintage-engine:jar:5.5.2:test
[INFO]    |  +- org.apiguardian:apiguardian-api:jar:1.1.0:test
[INFO]    |  +- org.junit.platform:junit-platform-engine:jar:1.5.2:test
[INFO]    |  \- junit:junit:jar:4.12:test
[INFO]    +- org.mockito:mockito-junit-jupiter:jar:3.1.0:test
[INFO]    +- org.hamcrest:hamcrest:jar:2.1:test
[INFO]    +- org.mockito:mockito-core:jar:3.1.0:test
[INFO]    |  +- net.bytebuddy:byte-buddy:jar:1.10.4:test
[INFO]    |  +- net.bytebuddy:byte-buddy-agent:jar:1.10.4:test
[INFO]    |  \- org.objenesis:objenesis:jar:2.6:test
[INFO]    +- org.skyscreamer:jsonassert:jar:1.5.0:test
[INFO]    |  \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO]    +- org.springframework:spring-core:jar:5.2.2.RELEASE:compile
[INFO]    |  \- org.springframework:spring-jcl:jar:5.2.2.RELEASE:compile
[INFO]    +- org.springframework:spring-test:jar:5.2.2.RELEASE:test
[INFO]    \- org.xmlunit:xmlunit-core:jar:2.6.3:test

here is the tree of my project.. it's a standard spring boot structure.. The Controller is under the web dir/package

.
├── java
│   └── com
│       └── neodem
│           └── orl
│               ├── collections
│               ├── config
│               ├── engine
│               │   ├── core
│               │   │   ├── actions
│               │   │   └── model
│               │   └── original
│               │       ├── actions
│               │       └── model
│               ├── service
│               └── web
└── resources
nabster
  • 1,561
  • 2
  • 20
  • 32
Vincent Fumo
  • 361
  • 1
  • 2
  • 9

10 Answers10

11

That resolved it for me. It did not recognize @Controller. It found every API after using @RestController instead. Paths for the UI are (assuming port 8080):
http://localhost:8080/swagger-ui/index.html
http://localhost:8080/v3/api-docs
http://localhost:8080/v3/api-docs.yaml

Procrastinator
  • 2,526
  • 30
  • 27
  • 36
Janumar
  • 202
  • 2
  • 7
7

It's because you're using springdoc-openapi-ui, it uses when you want to integrate springdoc-openapi with Swagger UI, so for check the results you should first add and enable Swagger UI then check the swagger link. like: http://localhost:8080/swagger-ui.html.

If you don't want swagger you must use springdoc-openapi-core instead of springdoc-openapi-ui.

In summary

Solution 1

  • Add and Enable Swagger UI
  • Check the Swagger Url ({server-address}:{port}/swagger-ui.html.)

Solution 2

  • Change dependency from springdoc-openapi-ui to springdoc-openapi-core

Your dependency must like below snippet:

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-core</artifactId>
    <version>1.1.44</version>
</dependency>

Solution 3

List the packages to include in the documentation by config

#Packages to include
springdoc.packagesToScan=com.neodem.orl.web

Also This link might be useful. (Documenting a Spring REST API Using springdoc-openapi)

  • 1
    Thank you. I've found the baeldung link to be a bit out of date since the springdoc project doesn't use the `-core` package anymore and they include it in the `springdoc-openapi-ui` package already. I want to use the `springdoc-openapi-ui` and swagger ui, and that does work but of course it says "No operations defined in spec!" – Vincent Fumo Jan 26 '20 at 19:51
  • also, I should add, when I follow the baeldung instructions and just use the `springdoc-openapi-core` package I get the same results.. (no APIs identified, controllers not scanned) – Vincent Fumo Jan 26 '20 at 19:53
6

I have found the solution in my case, and posted a the springdoc git Issue (https://github.com/springdoc/springdoc-openapi/issues/378). It reads (in part):

when defining a REST Controller, spring allows you to declare @RequestMapping(value = "/init") with no explicit Method and will accept a POST request. However, in your OpenApiResource class you make a call to calculatePath, in there (on line 129) you make a call to the spring RequestMappingInfo.getMethodsCondition() and in my case you get back no results (since the method wasn't explicitly defined in the annotation).. thus no request method => no path calculated.

If I explicitly define the method: @RequestMapping(value = "/init", method = RequestMethod.POST) everything works as expected.

so the solution is to explicitly declare the Method in the @RequestMapping

Vincent Fumo
  • 361
  • 1
  • 2
  • 9
  • 1
    This looks like a poor API design. If you don't define an HTTP Method, it means your API is accepting all the HTTP Methods. Is it really the kind of API you want to expose to your clients? – brianbro Jan 27 '20 at 16:16
  • 3
    victim blaming in software... yay – Vincent Fumo Jan 28 '20 at 18:14
  • That makes no sense. What if your controller has GET, PUT, POST, DELETE... requests (@GetMapping, @PutMapping, @PostMapping, @DeleteMapping, ...)? How can you explicitly mark it with `method = RequestMethod.POST`. – pixel Oct 18 '21 at 21:40
4

I faced same problem when i try to develop in Spring Boot 3 env. Swagger-UI and docs not working without any message and log. Then I investigate and find this solution. I must migrate Swagger UI 2.0 new version for Spring Boot 3.

Docs: https://springdoc.org/v2

New Dependency:

   <dependency>
      <groupId>org.springdoc</groupId>
      <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
      <version>2.0.0</version>
   </dependency>

And Also document say: For the integration between spring-boot and swagger-ui, add the library to the list of your project dependencies (No additional configuration is needed)

Note: If you need to use native image usage then use this properties:

springdoc.enable-native-support=true
Talha Dilber
  • 117
  • 1
  • 3
3

Just to add that I had the same issue and solved by replacing @Controller by @RestController.

Gardella Juan
  • 382
  • 5
  • 12
  • 2
    I use @RestController and still get 404 after adding the springdoc-openapi-ui dependency to my pom – pixel Oct 18 '21 at 21:41
2

It is: Instead of:

@GetMapping(BookConfig.BOOK_ENDPOINT)

You must do:

@RequestMapping(value = BookConfig.BOOK_ENDPOINT, method = RequestMethod.GET)

This was a major pain to discover the root cause. OpenAPI needs to enhance its framework to support Spring's latest annotation version. It has actually been there for quite some time, already. Less typing is the way to go.

1

Fix paths-to-match to scan APIs as follows:

springdoc:
  swagger-ui.path: swagger-ui
  api-docs.path: /booking
  paths-to-match: /booking/v1/**  >>>> (/booking/v1)is the prefix path of rest apis defined in controller
Tohid Makari
  • 1,700
  • 3
  • 15
  • 29
1

Regarding the error springdoc openapi No operations defined in spec!, I got this issue. The reason in my case is during refactoring the code I changed the controller's package but I have not updated the Swagger Configuration that I defined. When I gave the correct controller in .packagesToScan(.......) in GroupedOpenApi.builder()..... the swagger ui started showing the endpoints :)

Prakhya
  • 21
  • 3
1

I had similar issue and I solved putting my main class in the root of my package

.
├── java
│   └── com
│       └── neodem
│           └── orl
│               ├── collections
│               ├── config
│               ├── engine
│               │   ├── core
│               │   │   ├── actions
│               │   │   └── model
│               │   └── original
│               │       ├── actions
│               │       └── model
│               ├── service
│               └── web
│               └── MainApp.java <- this is important
└── resources
Adán Escobar
  • 1,729
  • 9
  • 15
1

If you want to pick up controllers from more Java packages, make sure to include your packages in the component scan when starting your application.

Spring doc picks up endpoints only from the beans loaded into the application.

@ComponentScan(basePackages={<packagesWithControllers>})

Džan Operta
  • 399
  • 2
  • 11