jbretsch / openapi-route-definition-locator

A RouteDefinitionLocator for Spring Cloud Gateway which creates route definitions dynamically based on OpenAPI (aka Swagger) definitions served by backend (micro)services.
MIT License
16 stars 5 forks source link

Selectively choose among provided OpenAPI specification #12

Open zlatozar opened 2 months ago

zlatozar commented 2 months ago

Is there a way to select from provided OpenAPI only endpoints that are marked with specific attribute? For example I would like to expose endpoint that has attribute x-gateway-name with value ui-gateway.

jbretsch commented 2 months ago

That's currently not supported. You can customize but not filter route definitions.

It's this way because I wanted to start simple. But your question makes me think that a filter mechanism can be expected to exist.

One can imagine different changes to the code in the vicinity of OpenApiRouteDefinitionLocator.java#L88-L91 where the customizers are called.

  1. Analogous to the route definition customizers, the library could allow the registration of route definition filters. Directly before a route definition is passed to the customizers, it would be passed to the registered filters. If any of those filters returns false, the route definition is skipped.
  2. Same as 1. but the filters are called after the customizers. This would allow filtering based on information that is added to the route definition by the customizers. But this order may be counterintuitive. I can imagine that most people would expect filters to be applied first in order the save customizing something that gets filtered out anyway.
  3. Allow customizing (transforming) and filtering a route definition in the same step. Something like letting the method OpenApiRouteDefinitionCustomizer.java::customize return the potentially modified route definition with returning null meaning: ignore this route definition.

More variations of the above ideas can be imagined.

I will think a little bit more about some details of the above options.

Do you already have some thoughts about those options that you want to share?

jbretsch commented 2 months ago

There is a hacky way to exclude specific API operations (endpoints) from being published in (or being reachable via) the Spring Cloud Gateway which works with the current version of the OpenAPI Route Definition Locator library and that is to use the configuration mechanism described in the section Additional RouteDefinition attributes in OpenAPI definitions and add a predicate that can never be fulfilled to those API operations in the OpenAPI definition that should be ignored, e.g.:

x-gateway-route-settings:
  predicates:
    - Before=1970-01-01T00:00:00.00+00:00

NOTE: I am by no means advocating to use this hack. It's just a funny observation.

But based on the above hack, I can imagine to add an enabled flag to the x-gateway-route-settings which would offer a very simple way of deactivating (i.e. hiding) certain API operations. This configuration based option should still be supplemented by some programmatic (i.e. dynamic) option to filter API operations as outlined in my above comment, I think.

zlatozar commented 2 months ago

Thanks for the quick answer @jbretsch! Point one sounds right to me - why to process something as you do not want it. If you allow me, I would like to share a few thoughts from my side.

  1. I will expect to see in GW log what is the criteria of selecting
  2. Why not to treat attribute values as list of labels? What I mean. Imagine that I have 3 gateways as in our use case, ui-gateway, mobile-gateway and b2b. Our "core" microservice should expose most of the time at least to 2 of them. So the the easiest way is to describe it in OpenApi spec like this: x-gateway-name: ui-gateway, mobile-gateway

PS I just randomly choose attribute name to be x-gateway-name. May be it should be part of x-gateway-route-settings... you know better :)

jbretsch commented 2 months ago

Hi @zlatozar!

Thanks for your feedback.

I hadn’t previously considered a setup involving multiple API gateways, but I see how it could be beneficial in certain scenarios. Your suggestion about using labels is intriguing, and I’ve given some thought to how we can implement it while maintaining backward compatibility.

Here’s what I propose:

We introduce two new optional settings in the x-gateway-route-settings section of the OpenAPI definitions:

x-gateway-route-settings:
   # Optional. Default: true
   # true -> Publish in gateways; all of them or only those specified in `gateway-names`.
   # false -> Don't publish in gateways; not even those specified in `gateway-names`.
   enabled: true / false

   # Optional. Default: null.
   # null -> Publish in all gateways.
   # [] -> Publish in no gateway.
   # ["foo", "bar"] -> Publish in the gateways named "foo" and "bar".
   gateway-names:          
      - ui-gateway
      - mobile-gateway
      - b2b

Additionally, a new (optional) property would be added to the gateway's application properties:

# application.yaml in gateway.
openapi-route-definition-locator:
   # Optional.
   # If an API operation is configured for specific `gateway-names` and this gateway doesn't have
   # a name assigned via `gateway-name`, no route will be configured for that operation in this gateway.
   gateway-name: ui-gateway

To further enhance flexibility, I suggest adding an OpenApiRouteDefinitionFilter interface, similar to the existing OpenApiRouteDefinitionCustomizer interface (as discussed in this comment). These filters would be invoked just before the customizers.

Would this approach meet your requirements?