Skip to content
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

Adds a path prefix routing object. #412

Merged
merged 7 commits into from
May 22, 2019

Conversation

mikkokar
Copy link
Contributor

@mikkokar mikkokar commented May 16, 2019

Adds a new routing object called "PathPrefixRouter". It performs a routing decision based on longest path prefix.

Example usage:

    type: PathPrefixRouter
    config:
      routes:
        - { prefix: /, destination: root }
        - { prefix: /foo/, destination: foo }

The destination can be also inlined. Like so:

    type: PathPrefixRouter
    config:
      routes:
        - { prefix: /, destination: root }
        - prefix: /styx/
          destination:
            type: StaticResponseHandler
            config:
              status: 200
              content: "Hello, from Styx"

mikkokar added 4 commits May 16, 2019 11:04
Add routingObjectDef utility method in favour of configBlock.
@mikkokar mikkokar force-pushed the path-prefix-router branch from 26ab88f to 845bd0e Compare May 16, 2019 10:24
@mikkokar mikkokar requested review from kvosper and dvlato May 16, 2019 10:32
public Optional<HttpHandler> route(LiveHttpRequest request) {
String path = request.path();

return routes.entrySet().stream()
Copy link
Contributor

@dvlato dvlato May 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we use floorEntry() with the default ordering ? That should return a correct path route.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is mimics the routing logic from BackendServicesRouter. It is important to keep both components identical until we deprecate BackendServicesRouter.

It is better to minimise the number of variables while migrating backend services router to the new routing object model.

Once the migration is successfully concluded and tested, we shall then optimise this part as a separate increment. Therefore we should leave this as it is. For now.

/**
* Resolves a routing object reference from route database.
*/
public class RouteRefLookup implements Function<RoutingObjectReference, HttpHandler> {
Copy link
Contributor

@dvlato dvlato May 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would consider creating an interface for this instead of implementing Function directly. This is not as much to have a slightly easier to read code but basically a solution to overcome the problem that the IDEs 'Find usages' will find any Function instead of only Function<RoutingObjectReference, HttpHandler>

@@ -44,28 +47,37 @@
*/
public class RoutingObjectFactory {
public static final ImmutableMap<String, Schema.FieldType> BUILTIN_HANDLER_SCHEMAS;
private static final ImmutableMap<String, HttpHandlerFactory> BUILTIN_HANDLER_FACTORIES;
public static final ImmutableMap<String, HttpHandlerFactory> BUILTIN_HANDLER_FACTORIES;
public static final Function<RoutingObjectReference, HttpHandler> DEFAULT_REFERENCE_LOOKUP = reference -> (request, ctx) -> Eventual.of(response(NOT_FOUND)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should move the Eventual.of(response(NOT_FOUND) down to a new line.

.map(Map.Entry::getValue);
}

public static class Factory implements HttpHandlerFactory {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've generally been using the convention that X.Factory builds instances of X, but here PathPrefixRouter seems to be just an internal component of the HttpHandler except that it is public, with the handler just being a lambda.

What is the reason for this divergence?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is to simplify unit testing.

Otherwise PathPrefixRouter would have to be a HttpHandler with a return type of Eventual<LiveHttpResponse>. This would complicate unit testing.

The Factory for every class in routing.handlers.* returns a routing object as a HttpHandler instance. From the consumer's point of view it doesn't matter if PathPrefixRouter is the underlying implementation, or merely just a part of it. But it being merely an internal component of an HttpHandler simplifies unit tests and the divergence is preferred.


handler.handle(HttpRequest.get("/x").build())
.toMono()
?.block()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
?.block()
.block()

toMono is a kotlin method with a non-nullable return type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay. Good catch. I'll change them.


handler.handle(HttpRequest.get("/foo/").build())
.toMono()
?.block()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
?.block()
.block()

toMono is a kotlin method with a non-nullable return type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


handler.handle(HttpRequest.get("/foo").build())
.toMono()
?.block()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
?.block()
.block()

val response = RouteRefLookup(routeDb).apply(RoutingObjectReference("handler1"))
.handle(get("/").build())
.toMono()
?.block()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
?.block()
.block()

public HttpHandler apply(RoutingObjectReference route) {
return this.routeDatabase.get(route.name())
.map(RoutingObjectRecord::getHandler)
.orElse((x, y) -> Eventual.of(response(NOT_FOUND)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During discussion we noticed that there may be a bug here and in many similar circumstances in which a LiveHttpRequest is not having its body consumed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this handler. However I will review the usage of other handlers separately.

@@ -36,21 +36,25 @@
* A StyxObjectStore based route reference lookup function.
*/
class RouteDbRefLookup implements RouteRefLookup {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation below here is incorrect on several lines.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been fixed.

@mikkokar mikkokar merged commit d429407 into ExpediaGroup:master May 22, 2019
@mikkokar mikkokar deleted the path-prefix-router branch May 22, 2019 13:29
dvlato pushed a commit that referenced this pull request Jul 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants