I'm building microservices project using spring boot 3 and I have found some problems from api gateway.
when I type each service port I get swagger ui documentation but when I try access it's documentation from api the gateway I get this error "Failed to load remote configuration."
here is my springdoc config for
api-gatway :
<!-- Swagger documentation Dependencies -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-common</artifactId>
<version>3.0.0</version>
<scope>compile</scope>
</dependency>
gateway config:
#Configuration
#Primary
public class SwaggerConfig {
public static final String API_URI = "/v3/api-docs";
private final RouteDefinitionLocator routeLocator;
public SwaggerConfig(RouteDefinitionLocator routeLocator) {
this.routeLocator = routeLocator;
}
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("1.0");
return swaggerResource;
}
}
gateway routing :
#Bean
DiscoveryClientRouteDefinitionLocator dynamicRoutes(ReactiveDiscoveryClient rdc, DiscoveryLocatorProperties dlp){
return new DiscoveryClientRouteDefinitionLocator(rdc,dlp);
}
backend services :
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.9</version>
</dependency>
expecting : enter image description here
but what i get
enter image description here
enter image description here
Related
I need to use a specific url for Swagger-ui. I have tried to use the property "springdoc.swagger-ui.path" but it only redirects.
application.propperties:
springdoc.swagger-ui.path=/helloWorld/swagger
Url in browser: http://localhost:8181/helloWorld/swagger
but the url changes to the following when hits enter button:
http://localhost:8181/manager/swagger-ui/index.html?configUrl=/manager/swagger/swagger.json/swagger-config
the question is, how can i make the path be only http://localhost:8181/helloWorld/swagger/index.html or http://localhost:8181/helloWorld/swagger once i've hit enter (I need the word "swagger-ui" and configUrl disappear)?
I`m uisng Springdoc and even tried with springfox
Pom.xml
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.2</version>
</dependency>
application.propperties:
springdoc.api-docs.path=/helloWorld/swagger/swagger.json
springdoc.swagger-ui.path=/helloWorld/swagger
I guess it's version dependent regarding the answer.
if you're using 2.8.0 and above, you could use following dependencies:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
And create a controller which will just redirect to the main swagger page, like this:
#Controller
public class SwaggerController {
#RequestMapping("/")
public String index() {
return "redirect:swagger-ui.html";
}
}
But if you use 2.6.1 or like that you can personalize your swagger configuration java class extending WebMvcConfigurerAdapter and overwriting the addViewController, like this:
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController(MAIN_URL, SWAGGER_UI_URL).setContextRelative(true);
registry.addRedirectViewController(MAIN_URL + "/", SWAGGER_UI_URL).setContextRelative(true);
}
That's it. Both approaches used the same dependencies but with different versions.
I've implemented a controller using #BasePathAwareController which also takes advantage of Spring Data REST (for finds to expose sort/size etc.)
along with some custom endpoints (for updates etc.). The application is working as expected and the endpoints Spring
Data REST generates are working as expected and I can see the self links appear in the responses, however, i can't see
these endpoints in Swagger UI. I can just see my custom endpoints
defined in my Controller.
According to this post I need to use Swagger 3.0.0-SNAPSHOT with #EnableSwagger2WebMvc
Here's my configurations:
My app.yml:
spring:
data:
rest:
basePath: /api/v1
My POM file:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/>
</parent>
<properties>
<springfox.swagger.version>3.0.0-SNAPSHOT</springfox.swagger.version>
</properties>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox.swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox.swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-data-rest</artifactId>
<version>${springfox.swagger.version}</version>
</dependency>
Swagger Config File:
#Configuration
#Import(SpringDataRestConfiguration.class)
#EnableSwagger2WebMvc
public class SwaggerConfig {
#Bean
public Docket api(ServletContext servletContext) {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("my.package.name"))
.paths(PathSelectors.any())
.build().apiInfo(apiEndPointsInfo());
}
private ApiInfo apiEndPointsInfo() {
return new ApiInfoBuilder().title("My App REST API's")
.description("My App REST API's")
.version("1.0").build();
}
}
My repo:
#RepositoryRestResource(exported=true, collectionResourceRel="group", path="group")
public interface GroupRepository extends JpaRepository<Group, Long>, JpaSpecificationExecutor<Group> {
}
Why can't i see the default endpoints that Spring Data REST produces?
I found the issue to my problem. I wasn't aware that Spring Data REST doesn't expose the generated endpoints under the controller package name I had specified here:
.apis(RequestHandlerSelectors.basePackage("my.package.name"))
so when I changed the above line to:
.apis(RequestHandlerSelectors.any())
and I could see the JPA respository endpoints.
I already went through the link: Unable to connect to Command Metric Stream for Hystrix Dashboard with Spring Cloud and tried few options, but nothing worked out for yet.
I am developing Spring Cloud Code + Hystrix + Turbine.
Could you please let me know what is the issue ? I am using Spring Boot v2.0.4.RELEASE.
HystrixDashboardApplication.java
#EnableTurbine
#EnableHystrixDashboard
#SpringBootApplication
public class HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class, args);
}
}
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
tollrate-billboard application has the following code
TollrateBillboardApplication.java
#EnableCircuitBreaker
#SpringBootApplication
#EnableEurekaClient
public class TollrateBillboardApplication {
public static void main(String[] args) {
SpringApplication.run(TollrateBillboardApplication.class, args);
}
}
DashboardController.java
#Controller
public class DashboardController {
#LoadBalanced
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
#Autowired
private RestTemplate restTemplate;
#HystrixCommand(fallbackMethod = "getTollRateBackup")
#RequestMapping("/dashboard")
public String GetTollRate(#RequestParam int stationId, Model m) {
TollRate tr = restTemplate.getForObject("http://pluralsight-toll-service/tollrate/" + stationId, TollRate.class);
System.out.println("stationId: " + stationId);
m.addAttribute("rate", tr.getCurrentRate());
return "dashboard";
}
public String getTollRateBackup(#RequestParam int stationId, Model m) {
System.out.println("Fallback operation called");
m.addAttribute("rate", "1.00");
return "dashboard";
}
}
bootstrap.properties
spring.application.name=pluralsight-tollrate-billboard
application.properties
server.port=8082
# eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
#http://cloud.spring.io/spring-cloud-static/Finchley.RELEASE/single/spring-cloud.html#_environment_changes
management.endpoints.web.exposure.include=hystrix.stream
CURL Command Result:
curl "http://localhost:8085/clusters"
output
[
{
"name": "PLURALSIGHT-FASTPASS-CONSOLE",
"link": "http://localhost:8085/turbine.stream?cluster=PLURALSIGHT-FASTPASS-CONSOLE"
},
{
"name": "PLURALSIGHT-TOLLRATE-BILLBOARD",
"link": "http://localhost:8085/turbine.stream?cluster=PLURALSIGHT-TOLLRATE-BILLBOARD"
}
]
EDIT-1::, I am using "hystrix-turbine"
#EnableTurbineStream
#SpringBootApplication
public class HystrixTurbineApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixTurbineApplication.class, args);
}
}
Now, I'm getting below error:
2018-09-03 22:23:45.808 WARN 2820 --- [nio-8085-exec-5] ashboardConfiguration$ProxyStreamServlet : Failed opening connection to http://localhost:8085/turbine.stream?cluster=PLURALSIGHT-FASTPASS-CONSOLE : 404 : HTTP/1.1 404
2018-09-03 22:23:45.808 WARN 2820 --- [nio-8085-exec-2] ashboardConfiguration$ProxyStreamServlet : Failed opening connection to http://localhost:8085/turbine.stream?cluster=PLURALSIGHT-FASTPASS-CONSOLE : 404 : HTTP/1.1 404
#Sayali I tried recreating the error in my own system and I managed to get it working, here are a few checks you can make:
1) The URL in your 1st screenshot is incorrect. Your stream URL in the Hystrix Dashboard should be:
http://localhost:8085/turbine.stream?cluster=PLURALSIGHT-TOLLRATE-BILLBOARD
The url should be pointing to the port of the dashboard application that has #EnableTurbine annotation in your main class.
2) Check if you are getting a response for:
http://localhost:8082/actuator/hystrix.stream
(use your browser for this)
(this should be coming from the application you have enabled hystrix on using #EnableCircuitBreaker)
If you're getting pings, then atleast your hystrix stream is accessible.
If not,
Check if you have: org.springframework.boot:spring-boot-starter-actuator in dependencies and
make sure you have the below property set in application.properties file of the application that has #EnableCircuitBreaker in the main class:
management.endpoints.web.exposure.include= hystrix.stream, info, health
Check the URL again.
3) Please get the turbine section working before moving to turbine streams, so as of now, you can make the following change:
#EnableTurbine // instead of #EnableTurbineStream
#SpringBootApplication
public class HystrixTurbineApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixTurbineApplication.class, args);
}
}
Also, to use TurbineStream:
you might want to have your Hystrix commands push metrics to Turbine.
Spring Cloud enables that with messaging. To do so on the client, add
a dependency to spring-cloud-netflix-hystrix-stream and the
spring-cloud-starter-stream-* of your choice.
refer: http://cloud.spring.io/spring-cloud-static/Finchley.SR1/single/spring-cloud.html#_turbine_stream
I hope this helps. Please comment to help me know if this worked for you.
sorry late reply.
Add following configuration to instance that serve hystrix.stream
hystrix.dashboard.proxyStreamAllowList: '**'
I am having trouble using swagger with Apache CXF, JAX-RS services.
beans.xml:
<bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"/>
<bean id="apiListingResourceJSON" class="com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON"/>
<bean id="apiDeclarationProvider" class="com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider"/>
Example use:
#Path("/")
#Api(value="/", description="VenturoSoft eMustering Services")
public class Service {
final static Logger logger = Logger.getLogger(Service.class);
#GET
#Path("/echo/{input}")
#Produces(MediaType.TEXT_PLAIN_VALUE)
#Consumes(MediaType.TEXT_PLAIN_VALUE)
#ApiOperation(value = "Get Ping", response = String.class)
public String ping(#PathParam("input") String input) {
return PingImpl.ping(input);
}
Pom.xml:
<dependency>
<groupId>com.wordnik</groupId>
<artifactId>swagger-jaxrs_2.10</artifactId>
<version>1.3.12</version>
</dependency>
<dependency>
<groupId>com.mangofactory</groupId>
<artifactId>swagger-springmvc</artifactId>
<version>1.0.2</version>
</dependency>
Run:
mvn tomcat7:run-war
But when I load:
http://localhost:13000/jaxrs-service/api
I get no response.
http://localhost:13000/jaxrs-service/echo/echoSomething
Works as desired.
You're looking at some very old dependencies. From your code, it looks like you're using JAXRS. If that's the case, the latest dependencies should be:
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jaxrs</artifactId>
<version>1.5.4</version>
</dependency>
Please follow the JAXRS sample here:
https://github.com/swagger-api/swagger-samples/tree/master/java/java-jaxrs-cxf
Which should show you how to correctly configure the server.
I have a Standalone Jersey server running at the beginning of my JunitTest. I'm testing if my JaxRS controller works, as well as my custom HttpClient. Please note that I've always been able to use this JaxRsResourceController embedded in glassfish.
Here is the JaxRsController (light version)
#Path("root")
public class JaxRsResourceController implements
ResourceController<HttpServletRequest> {
#Context
private UriInfo context;
#Context
HttpServletRequest request;
#Context
HttpServletResponse response;
#GET
public String hello(){
System.out.println("Uri is "+this.context.getBaseUri().toString());
return "Hello "+peoples;
}
}
I have no problem with the client, but when I start the server, I have :
GRAVE: The following errors and warnings have been detected with resource and/or provider classes:
SEVERE: Missing dependency for field: javax.servlet.http.HttpServletRequest com.robustaweb.library.rest.controller.implementation.JaxRsResourceController.request
SEVERE: Missing dependency for field: javax.servlet.http.HttpServletResponse com.robustaweb.library.rest.controller.implementation.JaxRsResourceController.response
at com.sun.jersey.api.container.httpserver.HttpServerFactory.create(HttpServerFactory.java:172)
at com.robustaweb.library.rest.server.JerseyServer.startServer(JerseyServer.java:44)
Basically it says that at the #Context injection time, there is no dependency on the HttpServletRequest.
However if I remove the #Context annotations on request and response, but keep it for UriInfo context, it's ok, and I can read the Uri.
I changed a few times the Maven pom wich is now to force the libs in:
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
</dependencies>
Any idea ?
servlet dependencies were separated to another module, try adding
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.14</version>
</dependency>
to your pom.
It was not easy, but I found out. The thing is that in my JUnit test, I was creating the server like this :
HttpServer server = HttpServerFactory.create(url);
But that way, you create a lightweight container that does not have servlet containers, and so is the failure reason. So in order to have it all, I used the jersey-test-framework that allow to use the Grizzly web container (or even Embedded glassfish).
Here is the maven :
<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
</dependency>
<!-- Unit test are using jersey server directly -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey.test.framework</groupId>
<artifactId>jersey-test-framework</artifactId>
<version>1.0.3</version>
<scope>test</scope>
</dependency>
</dependencies>
Here is the JerseyServerTest : note that it extends JerseyTest
public class JerseyServerTest extends JerseyTest {
protected String baseUri = "http://localhost:" + TestConstants.JERSEY_HTTP_PORT + "/";
public JerseyServerTest() throws Exception {
super("com.robustaweb.library.rest.controller");
/*
It's possible to NOT call the super() but to manually do :
1) ApplicationDescriptor appDescriptor = new ApplicationDescriptor()
.setRootResourcePackageName(resourcePackageName) // resource packages
.setContextPath(contextPath) //context of app
.setServletPath(servletPath); // context of spi servlet
2)setupTestEnvironment(appDescriptor);
*/
}
#Test
public void testHelloWorldRequest() {
SunRestClient client = new SunRestClient(baseUri + "root");
String result = client.GET("", null);
System.out.println(result);
}
#Test
public void testDeleteRequest() {
SunRestClient client = new SunRestClient(baseUri + "root");
String result = client.DELETE("john", null);
System.out.println(result);
}
}
And finally the Resource file, that contains #GET and #DELETE
#Path("root")
public class JaxRsController extends JaxRsResourceController{
List<String> peoples = new ArrayList<String>();
#GET
public String hello(){
System.out.println("Uri is "+getUri());
return "Hello "+peoples;
}
#DELETE
#Path("{name}")
public String deletePeople(#PathParam("name") String name){
System.out.println("deleting "+name);
this.peoples.remove(name);
return String.valueOf(peoples.size());
}
}
And now it works !
I had some help in this article, and there is a small chapter on the documentation. Beeing able to attach the source code of the Jersey framework really helped, so thantks to IntelliJ also.