question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Swagger-ui is incorrectly using a base path when you "Try Out" the api

See original GitHub issue

hi @dilipkrish

Thanks for responding. I really appreciate it. Followed the instructions as suggested:

1- Removed dependencies springfox-swagger-ui, springfox-swagger2 and springfox-spring-webmvc 2- Added springfox-boot-starter

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-boot-starter</artifactId>
	<version>3.0.0-SNAPSHOT</version>
 </dependency>

3- Removed @EnableSpringfoxWebMvc annotation from SwaggerConfig class.

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

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.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

@Configuration
public class SwaggerConfig {
	
	private static final Set<String> DEFAULT_PRODUCES_AND_CONSUMES = new HashSet<String>(
			Arrays.asList("application/json", "application/xml"));
	@Bean
	public Docket apiDocket() {
		return new Docket(DocumentationType.SWAGGER_2)  
				.select()                                  
				//.apis(RequestHandlerSelectors.any())
	            .apis(RequestHandlerSelectors.basePackage("com.github.abhinavmishra14"))
				.paths(PathSelectors.any())
				//Let's be specific to what we consumer and what we produce, instead of "*/*"
				.build().consumes(DEFAULT_PRODUCES_AND_CONSUMES).produces(DEFAULT_PRODUCES_AND_CONSUMES)
				.apiInfo(apiInfo());
	}

	private ApiInfo apiInfo() {
		return new ApiInfoBuilder()
				.title("Restful webservices using spring boot")
				.description("A demo restful webservice project using spring boot")
				.version("1.0")
				.license("Apache License Version 2.0")
				.licenseUrl("https://www.apache.org/licenses/LICENSE-2.0")
				.build();
	}
}

4- Updated contextPath in application.properties :

server.servlet.contextPath=/rwsspringboot

5- Restarted the spring boot app.

I can see the api-docs at : http://127.0.0.1:8181/rwsspringboot/v2/api-docs

Where basePath is -> “/rwsspringboot” And all endpoints also shows context path in url, e.g.: /rwsspringboot/hello

Hence, when i load swagger-ui at : http://127.0.0.1:8181/rwsspringboot/swagger-ui/index.html , i see the UI loaded properly. However, when i use “Try-out” option, this is what i see:

CURL: curl -X GET “http://127.0.0.1:8181/rwsspringboot/rwsspringboot/hello” -H “accept: application/json” Requsest URL: http://127.0.0.1:8181/rwsspringboot/rwsspringboot/hello

Notice the path in the URL above ^^^^

Error:

Response { “timestamp”: “2020-06-27T18:35:49.913+00:00”, “status”: 404, “error”: “Not Found”, “message”: “No message available”, “path”: “/rwsspringboot/rwsspringboot/hello” }

So, the problem is that, as soon as i add context path, i start seeing the context path twice in the request urls. I think basepath should remain “/” or it should not append “/rwsspringboot” in the endpoint path when basepath is already set: /rwsspringboot

Full APIDocs:

{
swagger: "2.0",
info: {
description: "A demo restful webservice project using spring boot",
version: "1.0",
title: "Restful webservices using spring boot",
license: {
name: "Apache License Version 2.0",
url: "https://www.apache.org/licenses/LICENSE-2.0"
}
},
host: "127.0.0.1:8181",
basePath: "/",
tags: [
{
name: "hello-controller",
description: "Hello Controller"
},
{
name: "post-controller",
description: "Post Controller"
},
{
name: "user-rest-controller",
description: "User Rest Controller"
}
],
consumes: [
"application/json",
"application/xml"
],
produces: [
"application/json",
"application/xml"
],
paths: {
/hello: {
get: {
tags: [
"hello-controller"
],
summary: "hello",
operationId: "helloUsingGET",
responses: {
200: {
description: "OK",
schema: {
type: "string"
}
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
},
404: {
description: "Not Found"
}
}
}
},
/sayHello: {
get: {
tags: [
"hello-controller"
],
summary: "hello",
operationId: "helloUsingGET_1",
parameters: [
{
name: "name",
in: "query",
description: "name",
required: true,
type: "string"
}
],
responses: {
200: {
description: "OK",
schema: {
type: "string"
}
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
},
404: {
description: "Not Found"
}
}
}
},
/sayHelloAgain: {
get: {
tags: [
"hello-controller"
],
summary: "helloViaGetMapping",
operationId: "helloViaGetMappingUsingGET",
parameters: [
{
name: "name",
in: "query",
description: "name",
required: true,
type: "string"
}
],
responses: {
200: {
description: "OK",
schema: {
type: "string"
}
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
},
404: {
description: "Not Found"
}
}
}
},
/sayHelloBean: {
get: {
tags: [
"hello-controller"
],
summary: "helloBeanViaGetMapping",
operationId: "helloBeanViaGetMappingUsingGET",
parameters: [
{
name: "name",
in: "query",
description: "name",
required: true,
type: "string"
}
],
responses: {
200: {
description: "OK",
schema: {
$ref: "#/definitions/Response"
}
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
},
404: {
description: "Not Found"
}
}
}
},
/sayHelloBean/pathvariable/{name}: {
get: {
tags: [
"hello-controller"
],
summary: "helloBeanViaGetMappingPathVariable",
operationId: "helloBeanViaGetMappingPathVariableUsingGET",
parameters: [
{
name: "name",
in: "path",
description: "name",
required: true,
type: "string"
}
],
responses: {
200: {
description: "OK",
schema: {
$ref: "#/definitions/Response"
}
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
},
404: {
description: "Not Found"
}
}
}
},
/users: {
get: {
tags: [
"user-rest-controller"
],
summary: "getAllUsers",
operationId: "getAllUsersUsingGET",
responses: {
200: {
description: "OK",
schema: {
type: "array",
items: {
$ref: "#/definitions/User"
}
}
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
},
404: {
description: "Not Found"
}
}
},
post: {
tags: [
"user-rest-controller"
],
summary: "createUsers",
operationId: "createUsersUsingPOST",
parameters: [
{
in: "body",
name: "user",
description: "user",
required: true,
schema: {
$ref: "#/definitions/User"
}
}
],
responses: {
200: {
description: "OK",
schema: {
$ref: "#/definitions/Response"
}
},
201: {
description: "Created"
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
},
404: {
description: "Not Found"
}
}
}
},
/users/{id}: {
get: {
tags: [
"user-rest-controller"
],
summary: "getUser",
operationId: "getUserUsingGET",
parameters: [
{
name: "id",
in: "path",
description: "id",
required: true,
type: "integer",
format: "int32"
}
],
responses: {
200: {
description: "OK",
schema: {
$ref: "#/definitions/EntityModel«User»"
}
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
},
404: {
description: "Not Found"
}
}
},
delete: {
tags: [
"user-rest-controller"
],
summary: "deleteUser",
operationId: "deleteUserUsingDELETE",
parameters: [
{
name: "id",
in: "path",
description: "id",
required: true,
type: "integer",
format: "int32"
}
],
responses: {
200: {
description: "OK",
schema: {
$ref: "#/definitions/Response"
}
},
204: {
description: "No Content"
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
}
}
}
},
/users/{id}/posts: {
get: {
tags: [
"post-controller"
],
summary: "getAllPostsForAUser",
operationId: "getAllPostsForAUserUsingGET",
parameters: [
{
name: "id",
in: "path",
description: "id",
required: true,
type: "integer",
format: "int32"
}
],
responses: {
200: {
description: "OK",
schema: {
type: "array",
items: {
$ref: "#/definitions/Post"
}
}
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
},
404: {
description: "Not Found"
}
}
},
post: {
tags: [
"post-controller"
],
summary: "createPost",
operationId: "createPostUsingPOST",
parameters: [
{
name: "id",
in: "path",
description: "id",
required: true,
type: "integer",
format: "int32"
},
{
in: "body",
name: "post",
description: "post",
required: true,
schema: {
$ref: "#/definitions/Post"
}
}
],
responses: {
200: {
description: "OK",
schema: {
$ref: "#/definitions/Response"
}
},
201: {
description: "Created"
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
},
404: {
description: "Not Found"
}
}
}
},
/users/{id}/posts/{postId}: {
get: {
tags: [
"post-controller"
],
summary: "getPostDetails",
operationId: "getPostDetailsUsingGET",
parameters: [
{
name: "id",
in: "path",
description: "id",
required: true,
type: "integer",
format: "int32"
},
{
name: "postId",
in: "path",
description: "postId",
required: true,
type: "integer",
format: "int32"
}
],
responses: {
200: {
description: "OK",
schema: {
$ref: "#/definitions/EntityModel«Post»"
}
},
401: {
description: "Unauthorized"
},
403: {
description: "Forbidden"
},
404: {
description: "Not Found"
}
}
}
}
},
definitions: {
EntityModel«Post»: {
type: "object",
properties: {
content: {
type: "string",
description: "Content must be at least 2 characters long",
minLength: 2,
maxLength: 2147483647
},
links: {
$ref: "#/definitions/Links"
}
},
title: "EntityModel«Post»"
},
EntityModel«User»: {
type: "object",
properties: {
birthdate: {
type: "string",
format: "date-time",
description: "Birthdate should be before current date"
},
links: {
$ref: "#/definitions/Links"
},
name: {
type: "string",
description: "Name must be at least 2 characters long",
minLength: 2,
maxLength: 2147483647
}
},
title: "EntityModel«User»"
},
Links: {
type: "object",
properties: {
empty: {
type: "boolean"
}
},
title: "Links"
},
Post: {
type: "object",
properties: {
content: {
type: "string",
description: "Content must be at least 2 characters long",
minLength: 2,
maxLength: 2147483647
}
},
title: "Post",
description: "Post description"
},
Response: {
type: "object",
properties: {
statusCode: {
type: "string"
},
statusMessage: {
type: "string"
}
},
title: "Response"
},
User: {
type: "object",
properties: {
birthdate: {
type: "string",
format: "date-time",
description: "Birthdate should be before current date"
},
name: {
type: "string",
description: "Name must be at least 2 characters long",
minLength: 2,
maxLength: 2147483647
}
},
title: "User",
description: "User description"
}
}
}```

**Here are all the dependencies in my project:**

```xml
<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-hateoas</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-rest-hal-browser</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>
		
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter</artifactId>
		    <exclusions>
		        <exclusion>
		            <groupId>org.springframework.boot</groupId>
		            <artifactId>spring-boot-starter-logging</artifactId>
		        </exclusion>
		    </exclusions>
		</dependency>
		
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>
		
		<dependency>
		    <groupId>org.apache.logging.log4j</groupId>
		    <artifactId>log4j-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>com.fasterxml.jackson.dataformat</groupId>
			<artifactId>jackson-dataformat-yaml</artifactId>
		</dependency>
		<dependency>
			<groupId>com.lmax</groupId>
			<artifactId>disruptor</artifactId>
			<version>3.4.2</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.dataformat</groupId>
			<artifactId>jackson-dataformat-xml</artifactId>
		</dependency>
		
		<!-- Dependency for swagger [Start]-->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-boot-starter</artifactId>
			<version>3.0.0-SNAPSHOT</version>
		</dependency>
		<!-- Dependency for swagger [End]-->
		
		<!-- For Hot Reloading -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		
		<dependency>
		    <groupId>org.apache.commons</groupId>
		    <artifactId>commons-lang3</artifactId>
		</dependency>
		
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>```

_Originally posted by @abhinavmishra14 in https://github.com/springfox/springfox/issues/3070#issuecomment-650601631_

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:13 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
abhinavmishra14commented, Jun 30, 2020

@dilipkrish thanks for the fix. I just took latest snapshots after https://github.com/springfox/springfox/commit/03a10e6c4ac8a38212d435b3e9827753134a89a4 commit.

its working with classpath and duplicate context path is also gone. I can also see content type option. This is working with DocumentationType.SWAGGER_2.

Thanks alot for fixing the issue. Appreciate it.

fixed

1reaction
dilipkrishcommented, Jul 2, 2020

This is good thanks for persisting the testing.

Read more comments on GitHub >

github_iconTop Results From Across the Web

SpringFox Swagger UI has wrong base url - Stack Overflow
I know the API list on the swagger-ui is populated from that one, but why it's injected to URL when we test the...
Read more >
API Host and Base Path - Swagger
REST APIs have a base URL to which the endpoint paths are appended. The base URL is defined by schemes , host and...
Read more >
Try it out button - URL path incorrect - Google Groups
I am able to see the neat swagger UI and it displays my resources ... (Incorrect URL) ... <param-name>swagger.api.basepath</param-name>
Read more >
Fixing Swagger UI "Try it out" Functionality When Deployed in ...
Perhaps this has something to do with how the proxy is configured which I don't have control. //For the time being, the base...
Read more >
PI97413: Specifying a trailing "/" on the API's basepath causes ...
Adding a trailing "/" to an API's base path generates a test URL on the Swagger UI test client that results in 404...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found