== Router

The javadoc:Router[] is the heart of Jooby and consist of:

- Routing algorithm (radix tree)
- One or more javadoc:Route[text="routes"]
- Collection of operator over javadoc:Route[text="routes"]

=== Route

A javadoc:Route[] consists of three part:

.Routes:
[source, java, role="primary"]
----
{
  
  // <1> <2>
  get("/foo", ctx -> {
    return "foo"; // <3>
  });

  // Get example with path variable
  get("/foo/{id}", ctx -> {
    return ctx.path("id").value();
  });
  
  // Post example
  post("/", ctx -> {
    return ctx.body().value();
  });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  
  // <1> <2>
  get("/foo") {
    "foo" // <3>
  }

  // Get example with path variable
  get("/foo/{id}") {
    ctx.path("id").value()
  }
  
  // Post example
  post("/") {
    ctx.body().value()
  }
}
----

<1> HTTP method/verb, like: `GET`, `POST`, etc...
<2> Path pattern, like: `/foo`, `/foo/{id}`, etc...
<3> Handler function

The javadoc:Route.Handler[text="handler"] function always produces a result, which is send it back
to the client.

==== Attributes

Attributes let you annotate a route at application bootstrap time. It functions like static metadata available at runtime:

.Java
[source, java, role="primary"]
----
{
  get("/foo", ctx -> "Foo")
    .attribute("foo", "bar");
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  get("/foo") {
    "Foo"
  }.attribute("foo", "bar")
}
----

An attribute consist of a name and value. Values can be any object.
Attributes can be accessed at runtime in a request/response cycle. For example, a security module might check for a role attribute.

.Java
[source, java, role="primary"]
----
{
  decorator(next -> ctx -> {
    User user = ...;
    String role = ctx.getRoute().attribute("Role"); 
    
    if (user.hasRole(role)) {
        return next.apply(ctx);
    }      
    
    throw new StatusCodeException(StatusCode.FORBIDDEN);                              
  });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
decorator(
  val user = ...
  val role = ctx.route.attribute("Role")

  if (user.hasRole(role)) {
    return next.apply(ctx)
  } else {      
    throw StatusCodeException(StatusCode.FORBIDDEN)
  }
}
----


In MVC routes you can set attributes via annotations:

.Java
[source, java, role="primary"]
----
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Role {
  String value();
}

@Path("/path")
public class AdminResource {

  @Role("admin")
  public Object doSomething() {
    ...
  }

}

{
  decorator(next -> ctx -> {
    System.out.println(ctx.getRoute().attribute("Role"));
  });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class Role (val value: String)

@Path("/path")
class AdminResource {

  @Role("admin")
  fun doSomething() : Any {
    ...
  }

}

{
  decorator {
    println(ctx.route.attribute("Role"))
  }
}
----

The previous example will print: admin.
You can retrieve all the attributes of the route by calling `ctx.getRoute().getAttributes()`.

Any runtime annotation is automatically added as route attributes following these rules:
- If the annotation has a value method, then we use the annotation’s name as the attribute name.
- Otherwise, we use the method name as the attribute name.


=== Path Pattern

==== Static

.Java
[source, java, role="primary"]
----
{
  get("/foo", ctx -> "Foo");
}
----

.Koltin
[source, kotlin, role="secondary"]
----
{
  get("/foo") { "Foo" }
}
----

==== Variable

.Single path variable:
[source, java, role="primary"]
----
{
  // <1>
  get("/user/{id}", ctx -> {
    int id = ctx.path("id").intValue(); // <2>
    return id;
  });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  // <1>
  get("/user/{id}") {
    val id = ctx.path("id").intValue() // <2>
    id
  }
}
----

<1> Defines a path variable `id`
<2> Retrieve the variable `id` as `int`

.Multiple path variables:
[source, java,role="primary"]
----
{
  // <1>
  get("/file/{file}.{ext}", ctx -> {
    String filename = ctx.path("file").value(); // <2>
    String ext = ctx.path("ext").value();   // <3>
    return filename + "." + ext;
  });
}
----

.Kotlin
[source, kotlin,role="secondary"]
----
{
  // <1>
  get("/file/{file}.{ext}") {
    val filename = ctx.path("file").value() // <2>
    val ext = ctx.path("ext").value()       // <3>
    filename + "." + ext
  }
}
----

<1> Defines two path variables: `file` and `ext`
<2> Retrieve string variable: `file`
<3> Retrieve string variable: `ext`

.Optional path variable:
[source, java, role="primary"]
----
{
  // <1>
  get("/profile/{id}?", ctx -> {
    String id = ctx.path("id").value("self"); // <2>
    return id;
  });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  // <1>
  get("/profile/{id}?") {
    val id = ctx.path("id").value("self") // <2>
    id
  }
}
----

<1> Defines an optional path variable `id`. The trailing `?` make it optional.
<2> Retrieve the variable `id` as `String` when present or use a default value: `self`.

The trailing `?` makes the path variable optional. The route matches:

- `/profile`
- `/profile/eespina`

==== Regex

.Regex path variable:
[source, java, role="primary"]
----
{
  // <1>
  get("/user/{id:[0-9]+}", ctx -> {
    int id = ctx.path("id").intValue(); // <2>
    return id;
  });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  // <1>
  get("/user/{id:[0-9]+}") {
    val id = ctx.path("id").intValue() // <2>
    id
  }
}`
----

<1> Defines a path variable: `id`. Regex expression is everything after the first `:`, like: `[0-9]+`
<2> Retrieve an int value

Optional syntax is also supported for regex path variable: `/user/{id:[0-9]+}?`:

- matches  `/user`
- matches `/user/123`

==== * Catchall

.catchall
[source, java, role="primary"]
----
{
  // <1>
  get("/articles/*", ctx -> {
    String catchall = ctx.path("*").value(); // <2>
    return catchall;
  });
  
  get("/articles/*path", ctx -> {
    String path = ctx.path("path").value(); // <3>
    return path;
  });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  // <1>
  get("/articles/*") {
    val catchall = ctx.path("*").value() // <2>
    catchall
  }
  
  get("/articles/*path") {
    val path = ctx.path("path").value()  // <3>
    path
  }
}
----

<1> The trailing `*` defines a `catchall` pattern
<2> We access to the `catchall` value using the `*` character
<3> Same example, but this time we named the `catchall` pattern and we access to it using `path` 
variable name.

[NOTE]
====
A `catchall` pattern must be defined at the end of the path pattern.
====
 
=== Handler

Application logic goes inside a javadoc:Route.Handler[text=handler]. A 
javadoc:Route.Handler[text=handler] is a function that accepts a javadoc:Context[text=context] 
object and produces a `result`.

A javadoc:Context[text=context] allows you to interact with the `HTTP Request` and manipulate the 
`HTTP Response`.

[NOTE]
====
Incoming request matches exactly **ONE** route handler. If there is no handler, produces a `404`
response.
====

.Java
[source,java,role="primary"]
----
{
  get("/user/{id}", ctx -> ctx.path("id").value());  // <1>
  
  get("/user/me", ctx -> "my profile");              // <2>
  
  get("/users", ctx -> "users");                     // <3>
  
  get("/users", ctx -> "new users");                 // <4>
}
---- 

.Kotlin
[source,kotlin,role="secondary"]
----
{
  get("/user/{id}") { ctx.path("id").value() }  // <1>
  
  get("/user/me") { "my profile" }              // <2>
  
  get("/users") { "users" }                     // <3>
  
  get("/users") { "new users" }                 // <4>
}
----

Output:

<1> `GET /user/ppicapiedra` => `ppicapiedra`
<2> `GET /user/me` => `my profile`
<3> Unreachable => override it by next route
<4> `GET /users` => `new users` not `users`

Routes with most specific path pattern (`2` vs `1`) has more precedence. Also, is one or more routes
result in the same path pattern, like `3` and `4`, last registered route hides/overrides previous route.

==== Decorator

Cross cutting concerns such as response modification, verification, security, tracing, etc. is available
via javadoc:Route.Decorator[].

A `decorator` takes the `next` handler in the pipeline and produces a `new` handler:

[source,java]
----
interface Decorator {
  Handler apply(Handler next);
}
----

.Timing decorator example:
[source,java,role="primary"]
----
{
  decorator(next -> ctx -> {
    long start = System.currentTimeMillis();       // <1>

    Object response = next.apply(ctx);             // <2>

    long end = System.currentTimeMillis();
    long took = end - start;

    System.out.println("Took: " + took + "ms");   // <3>

    return response;                              // <4>
  });
  
  get("/", ctx -> {
    return "decorator";
  });
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  /** Kotlin uses implicit variables: `ctx` and `next` */
  decorator {
    val start = System.currentTimeMillis()  // <1>

    val response = next.apply(ctx)          // <2>

    val end = System.currentTimeMillis()
    val took = end - start

    println("Took: " + took + "ms")         // <3>

    response                                // <4>
  }
  
  get("/") {
    "decorator"
  }
}
----

<1> Saves start time
<2> Proceed with execution (pipeline)
<3> Compute and print latency
<4> Returns a response

[NOTE]
====
One or more decorator on top of a handler produces a new handler.
====

==== Before

The javadoc:Route.Before[text=before] filter runs before a `handler`.

A `before` filter takes a `context` as argument and don't produces a response. It expected to operates
via side effects (usually modifying the HTTP response).

[source,java]
----
interface Before {
  void apply(Context ctx);
}
----

.Example
[source,java,role="primary"]
----
{
  before(ctx -> {
    ctx.setResponseHeader("Server", "Jooby");
  });

  get("/", ctx -> {
    return "...";
  });
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  before {
    ctx.setResponseHeader("Server", "Jooby")
  }

  get("/") {
    "..."
  }
}
----

==== After

The javadoc:Route.After[text=after] filter runs after a `handler`.

An `after` filter takes three arguments. The first argument is the `HTTP context`, the second
argument is the result/response from a **functional handler** or `null` for **side-effects** handler,
the third and last argument is an exception generates from handler.

It expected to operates via side effects, usually modifying the HTTP response (if possible) or
for cleaning/trace execution.  

[source,java]
----
interface After {
  void apply(Context ctx, Object result, Throwable failure);
}
----

.Functional Handler:
[source,java,role="primary"]
----
{
  after((ctx, result, failure) -> {
    System.out.println(result);          <1>
    ctx.setResponseHeader("foo", "bar"); <2>
  });

  get("/", ctx -> {
    return "Jooby";
  });
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  after {
    println("Hello $result")             <1>
    ctx.setResponseHeader("foo", "bar")  <2>
  }

  get("/") {
    "Jooby"
  }
}
----

<1> Prints `Jooby`
<2> Add a response header (modifies the HTTP response)

If the target handler is a **functional** handler modification of HTTP response is allowed it.

For **side effects** handler the after filter is invoked with a `null` value and isn't allowed to modify the HTTP response.

.Side-Effect Handler:
[source,java,role="primary"]
----
{
  after((ctx, result, failure) -> {
    System.out.println(result);          <1>
    ctx.setResponseHeader("foo", "bar"); <2>
  });

  get("/", ctx -> {
    return ctx.send("Jooby");
  });
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  after {
    println("Hello $result")             <1>
    ctx.setResponseHeader("foo", "bar")  <2>
  }

  get("/") {
    ctx.send("Jooby")
  }
}
----

<1> Prints `null` (no value)
<2> Produces an error/exception

Exception occurs because response was already started and its impossible to alter/modify it.

Side-effects handler are all that make use of family of send methods, responseOutputStream and responseWriter.

You can check whenever you can modify the response by checking the state of javadoc:Context[isResponseStarted]:

.Safe After:
[source,java,role="primary"]
----
{
  after((ctx, result, failure) -> {
    if (ctx.isResponseStarted()) {
      // Don't modify response
    } else {
      // Safe to modify response
    }
  });
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  after {
    if (ctx.responseStarted) {
      // Don't modify response
    } else {
      // Safe to modify response
    }
  }
}
----

[NOTE]
====
An after handler is always invoked.
====

The next examples demonstrate some use cases for dealing with errored responses, but keep in mind
that an after handler is not a mechanism for handling and reporting exceptions that's is a task
for an <<error-handler, Error Handler>>.

.Run code depending of success or failure responses:
[source,java,role="primary"]
----
{
  after((ctx, result, failure) -> {
    if (failure == null) {
      db.commit();                   <1>
    } else {
      db.rollback();                 <2>
    }
  });
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  after {
    if (failure == null) {
      db.commit()                    <1>
    } else {
      db.rollback()                  <2>
    }
  }
}
----

Here the exception is still propagated given the chance to the <<error-handler, Error Handler>> to jump in.

.Recover fom exception and produces an alternative output:
[source,java,role="primary"]
----
{
  after((ctx, result, failure) -> {
    if (failure instanceOf MyBusinessException) {
      ctx.send("Recovering from something");        <1>
    }
  });
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  after {
    if (failure is MyBusinessException) {
      ctx.send("Recovering from something")         <1>
    }
  }
}
----

<1> Recover and produces an alternative output

Here the exception wont be propagated due we produces a response, so error handler won't be execute it.

In case where the after handler produces a new exception, that exception will be add to the original exception as suppressed exception.

.Suppressed exceptions:
[source,java,role="primary"]
----
{
  after((ctx, result, failure) -> {
    ...
    throw new AnotherException();
  });

  get("/", ctx -> {
    ...
    throw new OriginalException();
  });

  error((ctx, failure, code) -> {
    Throwable originalException = failure;                       <1>
    Throwable anotherException  = failure.getSuppressed()[0];    <2>
  });
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  after {
    ...
    throw AnotherException();
  }

  get("/") { ctx ->
    ...
    throw OriginalException()
  }

  error { ctx, failure, code) ->
    val originalException = failure                              <1>
    val anotherException  = failure.getSuppressed()[0]           <2>
  }
}
----

<1> Will be `OriginalException`
<2> Will be `AnotherException`

==== Complete

The javadoc:Route.Complete[text=complte] listener run at the completion of a request/response cycle
(i.e. when the request has been completely read, and the response has been fully written).

At this point it is too late to modify the exchange further. They are attached to a running context
(not like a decorator/before/after filters).

.Example
[source, java, role="primary"]
----
{
   decorator(next -> ctx -> {
     long start = System.currentTimeInMillis();
     ctx.onComplete(context -> {                      <1>
       long end = System.currentTimeInMillis();       <2>
       System.out.println("Took: " + (end - start));
     });
   });
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
   decorator {
     val start = System.currentTimeInMillis()
     ctx.onComplete {                                 <1>
       val end = System.currentTimeInMillis()         <2>
       println("Took: " + (end - start))
     }
   }
}
----

<1> Attach a completion listener
<2> Run after response has been fully written

Completion listeners are invoked in reverse order.

=== Pipeline

Route pipeline (a.k.a route stack) is a composition of one or more decorator(s) tied to a single `handler`:

.Java
[source, java, role="primary"]
----
{
  // Increment +1
  decorator(next -> ctx -> {
    Number n = (Number) next.apply(ctx);
    return 1 + n.intValue();
  });

  // Increment +1
  decorator(next -> ctx -> {
    Number n = (Number) next.apply(ctx);
    return 1 + n.intValue();
  });
  
  get("/1", ctx -> 1); // <1>
  
  get("/2", ctx -> 2); // <2>
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  // Increment +1
  decorator {
    val n = next.apply(ctx) as Int
    1 + n
  }

  // Increment +1
  decorator {
    val n = next.apply(ctx) as Int
    1 + n
  }
  
  get("/1") { 1 } // <1>
  
  get("/2") { 2 } // <2>
}
----

Output:

<1> `/1` => `3`
<2> `/2` => `4`

Behind the scene, Jooby builds something like:

[source, java]
----
{
  // Increment +1
  var increment = decorator(next -> ctx -> {
    Number n = (Number) next.apply(ctx);
    return 1 + n.intValue();
  });

  Handler one = ctx -> 1;
  
  Handler two = ctx -> 2;
  
  Handler handler1 = increment.then(increment).then(one);
  Handler handler2 = increment.then(increment).then(two);
  
  get("/1", handler1);
  
  get("/2", handler2);
}
----

Any `decorator` defined on top of the handler will be stacked/chained into a new handler.

[NOTE]
.Decorator without path pattern
====

This was a hard decision to make, but we know is the right one. Jooby 1.x uses a path pattern to
define `filter`/`decorator`.

The `pipeline` in Jooby 1.x consists of multiple filters and handlers. They are match
sequentially one by one. The following `filter` is always executed in Jooby 1.x

.Jooby 1.x
[source, java]
----
{
   use("/*", (req, rsp, chain) -> {
     // remote call, db call 
   });

   // ...
}
----

Suppose there is a bot trying to access and causing lot of `404` responses (path doesn't exist).
In Jooby 1.x the `filter` is executed for every single request sent by the bot just to realize 
there is NO matching route and all we need is a `404`.

In Jooby 2.x this won't happen anymore. If there is a matching handler, the `pipeline` will be 
executed. Otherwise, nothing will do!

====

==== Order

Order follows the **what you see is what you get** approach. Routes are stacked in the way they were added/defined.

.Order example:
[source, java, role="primary"]
----
{
  // Increment +1
  decorator(next -> ctx -> {
    Number n = (Number) next.apply(ctx);
    return 1 + n.intValue();
  });

  get("/1", ctx -> 1);                // <1>
  
  // Increment +1
  decorator(next -> ctx -> {
    Number n = (Number) next.apply(ctx);
    return 1 + n.intValue();
  });

  get("/2", ctx -> 2);               // <2>
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  // Increment +1
  decorator {
    val n = next.apply(ctx) as Int
    1 + n
  }

  get("/1") { 1 }                // <1>
  
  // Increment +1
  decorator {
    val n = next.apply(ctx) as Int
    1 + n
  }

  get("/2") { 2 }                // <2>
}
----

Output:

<1> `/1` => `2`
<2> `/2` => `4` 

==== Scoped Decorator

The javadoc:Router[route, java.lang.Runnable] and javadoc:Router[path, java.lang.String, java.lang.Runnable] operators
are used to group one or more routes.
  
A `scoped decorator` looks like:

.Scoped decorator:
[source, java, role="primary"]
----
{
  // Increment +1
  decorator(next -> ctx -> {
    Number n = (Number) next.apply(ctx);
    return 1 + n.intValue();
  });

  routes(() -> {                          // <1>
    // Multiply by 2
    decorator(next -> ctx -> {
      Number n = (Number) next.apply(ctx);
      return 2 * n.intValue();
    });
    
    get("/4", ctx -> 4);                 // <2>
  });
  
  get("/1", ctx -> 1);                   // <3>
}
----

.Kotlin
[source, kotlin, role="secondary"]
----
{
  // Increment +1
  decorator {
    val n = next.apply(ctx) as Int
    return 1 + n
  }

  routes {                                // <1>
    // Multiply by 2
    decorator {
      val n = next.apply(ctx) as Int
      1 + n
    }
    
    get("/4") { 4 }               // <2>
  }
  
  get("/3") { 3 }                 // <3>
}
----

Output:

<1> Introduce a new scope via `route` operator
<2> `/4`  => `9`
<3> `/1`  => `2`

It is a normal `decorator` inside of one of the group operators.

=== Grouping routes

As showed previously, the javadoc:Router[route, java.lang.Runnable] operator push a new route `scope`
and allows you to selectively apply one or more routes.

.Route operator
[source,java,role="primary"]
----
{
  routes(() -> {   

    get("/", ctx -> "Hello");

  });
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
  routes {

    get("/") {
      "Hello"
    }

  }
}
----

Route operator is for grouping one or more routes and apply cross cutting concerns to all them.

In similar fashion the javadoc:Router[path, java.lang.String, java.lang.Runnable] operator groups
one or more routes under a common path pattern.

.Routes with path prefix:
[source,java,role="primary"]
----
{
   path("/api/user", () -> {    // <1>
   
     get("/{id}", ctx -> ...);  // <2>
   
     get("/", ctx -> ...);      // <3>
     
     post("/", ctx -> ...);     // <4>
     
     ...
   }); 
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
{
   path("/api/user") {     // <1>
   
     get("/{id}") { ...}   // <2>
   
     get("/") { ...}       // <3>
     
     post("/") { ...}      // <4>
     
     ...
   }); 
}
----

<1> Set common prefix `/api/user`
<2> `GET /api/user/{id}`
<3> `GET /api/user`
<4> `POST /api/user`

=== Composing routes

Composition is a technique for building modular applications. You can compose one or more
router/application into a new one.

Composition is available through the javadoc:Router[use, io.jooby.Router] operator:

.Composing
[source, java, role="primary"]
----
public class Foo extends Jooby {
  {
    get("/foo", Context::getRequestPath);
  }
}

public class Bar extends Jooby {
  {
    get("/bar", Context::getRequestPath);
  }
}

public class App extends Jooby {
  {
    use(new Foo());                     // <1>

    use(new Bar());                     // <2>

    get("/app", Context::getRequestPath);   // <3>
  }
}
----

.Kotlin
[source, kotlin,role="secondary"]
----
class Foo: Kooby({
   
  get("/foo") { ctx.getRequestPath() }

})

class Bar: Kooby({
  
  get("/bar") { ctx.getRequestPath() }

})

class App: Kooby({
  use(Foo())                       // <1>

  use(Bar())                       // <2>

  get("/app") { ctx.getRequestPath() } // <3>
})
----

<1> Imports all routes from `Foo`. Output: `/foo` => `/foo`

<2> Imports all routes from `Bar`. Output: `/bar` => `/bar`

<3> Add more routes . Output `/app` => `/app`


.Composing with path prefix
[source,java,role="primary"]
----
public class Foo extends Jooby {
  {
    get("/foo", Context::getRequestPath);
  }
}

public class App extends Jooby {
  {
    use("/prefix", new Foo());  // <1>
  }
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
class Foo: Kooby({
   
  get("/foo") { ctx.getRequestPath() }

})

class App: Kooby({

  use("/prefix", Foo())  // <1>

})
----

<1> Now all routes from `Foo` will be prefixed with `/prefix`. Output: `/prefix/foo` => `/prefix/foo`

[TIP]
====
Composition is a great option for modularization. You can easily develop/test/deploy each 
application independently and compose them all in another application.

We do provide <<mvc-api, MVC API>> as another alternative for modularization.
====

=== Dynamic Routing

Dynamic routing is looks similar to <<composition, composition>> but enabled/disabled routes at runtime
using a `predicate`.

Suppose you own two version of an `API` and for some time you need to support both: `old` and `new` API:

.Dynamic Routing
[source,java,role="primary"]
----
public class V1 extends Jooby {
  {
    get("/api", ctx -> "v1");
  }
}

public class V2 extends Jooby {
  {
    get("/api", ctx -> "v2");
  }
}

public class App extends Jooby {
  {
    use(ctx -> ctx.header("version").value().equals("v1"), new V1()); // <1>

    use(ctx -> ctx.header("version").value().equals("v2"), new V2()); // <2>
  }
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
class V1: Kooby({
  
  get("/api") { "v1" }

})

class V2: Kooby({
  
  get("/api") { "v2" }

})

class App: Kooby({

  use(ctx -> ctx.header("version").value().equals("v1"), V1()); // <1>

  use(ctx -> ctx.header("version").value().equals("v2"), V2()); // <2>

})
----

Output:

<1> `/api` => `v1`; when `version` header is `v1`
<2> `/api` => `v2`; when `version` header is `v2`

Done {love}!

=== Options

include::router-hidden-method.adoc[]

include::router-trust-proxy.adoc[]
