-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Allow extension of ApiResourceController by making its methods public #1189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
JHipster 3.0 needs this to be able to override "/swagger-resources" mapping in order to be able to aggregate APIs of micro services proxified by a Zuul proxy.
Reading though the jhipster issue this is exactly what the swagger-resources endpoint is meant to serve 🤘. It also serves a couple of other subtle swagger-ui configuration options so that the bundled-swagger-ui can be served. The reason it is package protected is that it is meant to be a closed system until the contract between the custom swagger-ui and the server is stable. It seems fairly close but I want to be sure its the right time to open it up. So is the idea that jhipster will subclass and override behavior by aggregating known "micro services" in what the jhipster issue ☝️ calls "monolith"? I need to read up some more about Zuul and how jhipster is using it, but for my understanding, could you explain a little bit how Zuul proxy is configured? Assuming for e.g. you have a |
Hi Dilip, Thanks for your responsiveness. In JH 3.0, we propose now to generate 3 types of apps;
In the future, we may offer other ways to provide the UI, but for the moment it's in the gateway. So here our problem is on the api gateway where we override /swagger-resources endpoint to expose proxified APIs /**
* REST controller for retrieving all registered microservices Swagger resources.
*/
@RestController
@ApiIgnore
public class GatewaySwaggerApiResource extends ApiResourceController {
private final Logger log = LoggerFactory.getLogger(GatewaySwaggerApiResource.class);
@Inject
private ProxyRouteLocator routeLocator;
@Inject
private DiscoveryClient discoveryClient;
/**
* GET /swagger-resources : get the currently registered microservices swagger resources
* (Override the Springfox provided /swagger-resources endpoint)
*
* @return the ResponseEntity with status 200 (OK) and with body the list of swagger resources
*/
@RequestMapping(value = "/swagger-resources",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@Override
public ResponseEntity<List<SwaggerResource>> swaggerResources() {
List<SwaggerResource> resources = new ArrayList<>();
//Add the default swagger resource that correspond to the gateway's own swagger doc
resources.add(swaggerResource("default", "/v2/api-docs", "2.0"));
//Add the registered microservices swagger docs as additional swagger resources
Map<String, String> routes = routeLocator.getRoutes();
routes.forEach((path, serviceId) -> {
resources.add(swaggerResource(serviceId, path.replace("**","v2/api-docs"), "2.0"));
});
return new ResponseEntity<>(resources, HttpStatus.OK);
}
private SwaggerResource swaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
} |
I have a hopefully better proposition: let's favour composition over inheritance by having a controller per endpoint this way we could replace the one we want with our own using component scan filters.
|
Could you elaborate? I was thinking along the same lines but slightly differently, may be we're thinking the same thing |
I have to test it, it may not work. First I would split current ApiResourceController into 3 controller classes:
Then in our case we would exclude ApiResourceController @ComponentScan(excludeFilters = @ComponentScan.Filter(value = ApiResourceController.class, type = ASSIGNABLE_TYPE)) Then we would provide our own controller /**
* REST controller for retrieving all registered microservices Swagger resources.
*/
@RestController
@ApiIgnore
public class GatewaySwaggerApiResource {
private final Logger log = LoggerFactory.getLogger(GatewaySwaggerApiResource.class);
@Inject
private ProxyRouteLocator routeLocator;
@Inject
private DiscoveryClient discoveryClient;
/**
* GET /swagger-resources : get the currently registered microservices swagger resources
* (Override the Springfox provided /swagger-resources endpoint)
*
* @return the ResponseEntity with status 200 (OK) and with body the list of swagger resources
*/
@RequestMapping(value = "/swagger-resources",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@Override
public ResponseEntity<List<SwaggerResource>> swaggerResources() {
List<SwaggerResource> resources = new ArrayList<>();
//Add the default swagger resource that correspond to the gateway's own swagger doc
resources.add(swaggerResource("default", "/v2/api-docs", "2.0"));
//Add the registered microservices swagger docs as additional swagger resources
Map<String, String> routes = routeLocator.getRoutes();
routes.forEach((path, serviceId) -> {
resources.add(swaggerResource(serviceId, path.replace("**","v2/api-docs"), "2.0"));
});
return new ResponseEntity<>(resources, HttpStatus.OK);
}
private SwaggerResource swaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
} |
@gmarziou I created a PR ☝️ for you to have a look at what I've done, before I pull it in. I suspect this approach might have a better chance at working in the long run. Let me know what you think. |
So after It gets pulled in your class would become an implementation of the |
Thanks it's better, I did not know the |
It works, now when I go to /swagger-resources I get: [
{
"name": "default",
"location": "/v2/api-docs",
"swaggerVersion": "2.0"
},
{
"name": "srv1",
"location": "/srv1/v2/api-docs",
"swaggerVersion": "2.0"
}
]
I haven't yet tested with /swagger-ui as I have a minor problem to solve but I guess it should work fine. and my provider is really simple: @Component
@Primary
public class GatewaySwaggerResourceProvider implements SwaggerResourcesProvider {
private final Logger log = LoggerFactory.getLogger(GatewaySwaggerResourceProvider.class);
@Inject
private ProxyRouteLocator routeLocator;
@Inject
private DiscoveryClient discoveryClient;
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
//Add the default swagger resource that correspond to the gateway's own swagger doc
resources.add(swaggerResource("default", "/v2/api-docs", "2.0"));
//Add the registered microservices swagger docs as additional swagger resources
Map<String, String> routes = routeLocator.getRoutes();
routes.forEach((path, serviceId) -> {
resources.add(swaggerResource(serviceId, path.replace("**","v2/api-docs"), "2.0"));
});
return resources;
}
private SwaggerResource swaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
} |
So now (as you can imagine) my question is when do you plan to release this? |
🤘 The plan is to release by 1st of March (2.4.0) but I hope to release it this weekend as soon as it iron out a couple of minor issues . |
That will be perfect for us, we plan to release JH 3.0 somewhere in March. |
…r-resources-provider Extracted SwaggerResourcesProvider to an interface
Hello,
JHipster 3.0 needs to extend ApiResourceController for overriding "/swagger-resources" mapping in order to be able to aggregate APIs of micro services proxified by a Zuul proxy.
For details, please see the end of this discussion in jhipster/generator-jhipster#2990
Thanks,
Gael