8000 Allow extension of ApiResourceController by making its methods public by gmarziou · Pull Request #1189 · springfox/springfox · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

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

Closed
wants to merge 1 commit into from

Conversation

gmarziou
Copy link

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

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.
@dilipkrish
Copy link
Member

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 customer, shopping-cart-service which serve the swagger specification each. Is the monolith a 3rd application that proxies requests to the real services?

@dilipkrish dilipkrish added the PR label Feb 26, 2016
@dilipkrish dilipkrish added this to the 2.4.0 milestone Feb 26, 2016
@gmarziou
Copy link
Author

Hi Dilip,

Thanks for your responsiveness.

In JH 3.0, we propose now to generate 3 types of apps;

  • a monolith app as in JH 2.x (it's noit part of our micro services architecture)
  • a backend micro service (no UI only REST endpoints) that registers to an Eureka server
  • an api gateway that holds 2 roles:
    • Zuul proxy for the backend micro services taking care of authentication, rate limiting, load balancing amongst backend instances, ...
    • serving the UI angular app

In the future, we may offer other ways to provide the UI, but for the moment it's in the gateway.
You can get more details about our architecture here.

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;
    }
}

@gmarziou
Copy link
Author

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.

  • ApiResourceController
  • ApiSecurityConfigurationController
  • ApiUiConfigurationController

@dilipkrish
Copy link
Member

Could you elaborate? I was thinking along the same lines but slightly differently, may be we're thinking the same thing

@gmarziou
Copy link
Author

I have to test it, it may not work.

First I would split current ApiResourceController into 3 controller classes:

  • ApiResourceController mapped on /swagger-resources
  • ApiSecurityConfigurationController mapped on /configuration/security
  • ApiUiConfigurationController mapped on /configuration/ui

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;
    }
}

dilipkrish added a commit that referenced this pull request Feb 27, 2016
Also created an default In-memory swagger resources provider that will be
available to be overridden by a @primary bean implementation for providing
aggregation of services

related to #1189
@dilipkrish
Copy link
Member

@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.

@dilipkrish
Copy link
Member

So after It gets pulled in your class would become an implementation of the SwaggerResourcesProvider interface and all you need to do is annotate your implementation as the @Primary bean

dilipkrish added a commit that referenced this pull request Feb 27, 2016
Also created an default In-memory swagger resources provider that will be
available to be overridden by a @primary bean implementation for providing
aggregation of services

closes #1189
@gmarziou
Copy link
Author

Thanks it's better, I did not know the @Primary annotation, it's very interesting.
I'll make some test and let you know.

@gmarziou
Copy link
Author

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;
    }

}

@gmarziou
Copy link
Author

So now (as you can imagine) my question is when do you plan to release this?

@dilipkrish
Copy link
Member

🤘 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 .

@gmarziou
Copy link
Author

That will be perfect for us, we plan to release JH 3.0 somewhere in March.

@gmarziou gmarziou closed this Feb 27, 2016
@gmarziou gmarziou deleted the extend-endpoints branch February 27, 2016 20:07
dilipkrish added a commit that referenced this pull request Feb 28, 2016
…r-resources-provider

Extracted SwaggerResourcesProvider to an interface
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0