public interface Chain
A chain object can't be used to handle requests.
It can be thought of as a Domain Specific Language (DSL), or API, for constructing a List<Handler>
.
To understand the concept of a all chain, it is important to understand that a Handler
can do one of three things:
Insert handlers
and delegate processing;next handler
.
Methods like Handlers.chain(ServerConfig, ratpack.func.Action)
take a function that acts on a Chain
, and return a Handler
.
The returned handler effectively just performs an insert of the handlers added to the chain during the action..
It is very common to use this API to declare the handlers for an application as part of startup via the RatpackServerSpec.handlers(Action)
method.
Chains may be backed by a registry
, depending on how the chain was constructed.
The RatpackServerSpec.handlers(Action)
method backs the chain instance with the server registry.
The backing registry can be obtained via getRegistry()
on the chain instance.
This mechanism allows access to “supporting objects” while building the chain.
Methods such as all(Class)
also allow obtaining all implementations from the registry to use.
This can be useful when using the Guice integration (or similar) to allow all instance to be dependency injected through Guice.
The most basic method of Chain API is the all(Handler)
method.
The word “all” represents that all requests reaching this point in the chain will flow through the given handler.
This is in contrast to methods such as path(String, Handler)
that will only the request through the given handler if the request path matches.
Methods such as path(String, Handler)
, when(Predicate, Action)
etc. are merely more convenient forms of all(Handler)
and use of the static methods of Handlers
.
For each method that takes a literal Handler
, there exists a variant that takes a Class<? extends Handler>
.
Such methods obtain an instance of the given handler by asking the chain registry for an instance of the given type.
This is generally most useful if the chain registry is backed by some kind of dependency injection mechanism (like Google Guice)
that can construct the handler and inject its dependencies as needed.
Methods such as get(String, Handler)
, prefix(String, Action)
, accept a string argument as a request path binding specification.
These strings can contain symbols that allow PathTokens
to be captured and for path binding to be dynamic.
For example, the path string "foo/:val"
will match paths such as "foo/bar"
, "foo/123"
or indeed "foo/«anything»"
.
The following table describes the types of symbols that can be used in path strings…
Path Type | Syntax | Example |
---|---|---|
Literal | foo |
"foo" |
Regular Expression Literal | ::«regex» |
"foo/::\d+" |
Optional Path Token | :«token-name»? |
"foo/:val?" |
Mandatory Path Token | :«token-name» |
"foo/:val" |
Optional Regular Expression Path Token | :«token-name»?:«regex» |
"foo/:val?:\d+" |
Mandatory Regular Expression Path Token | :«token-name»:«regex» |
"foo/:val:\d+" |
The following example shows different kinds of binding paths in action.
import ratpack.test.embed.EmbeddedApp;
import com.google.common.base.MoreObjects;
import com.google.common.io.BaseEncoding;
import java.util.Arrays;
import java.util.Locale;
import static org.junit.Assert.*;
public class Example {
public static void main(String... args) throws Exception {
EmbeddedApp.fromHandlers(c -> c
.get("favorites/food", ctx -> ctx.render("pizza")) // Literal
.get("favorites/::colou?r", ctx -> ctx.render("blue")) // Regular expression literal
.get("optionalToken/:tkn?", ctx -> ctx.render(ctx.getPathTokens().toString())) // Optional path token
.get("greeting/:name?", ctx -> // Optional path token with default handling
ctx.render("Hello " + MoreObjects.firstNonNull(ctx.getPathTokens().get("name"), "world"))
)
.get("convert/hex/:tkn", ctx -> // Mandatory path token
ctx.render("Hello " + BaseEncoding.base64().encode(ctx.getPathTokens().get("tkn").getBytes("UTF-8")))
)
.get("pi/:precision?:[\\d]+", ctx -> // Optional regular expression path token
ctx.render(String.format(Locale.ENGLISH, "%1." + MoreObjects.firstNonNull(ctx.getPathTokens().get("precision"), "5") + "f", Math.PI))
)
.get("sum/:num1:[\\d]+/:num2:[\\d]+", ctx -> // Mandatory regular expression path tokens
ctx.render(
Arrays.asList("num1", "num2")
.stream()
.map(it -> ctx.getPathTokens().get(it))
.mapToInt(Integer::valueOf)
.sum() + ""
)
)
).test(httpClient -> {
assertEquals("pizza", httpClient.getText("favorites/food")); // Literal value matched
assertEquals("blue", httpClient.getText("favorites/color")); // Regular expression literal matched
assertEquals("blue", httpClient.getText("favorites/colour")); // Regular expression literal matched
assertEquals("{tkn=val}", httpClient.getText("optionalToken/val")); // Optional path token with value specified
assertEquals("{tkn=}", httpClient.getText("optionalToken/")); // Optional path token with trailing slash treated as empty string
assertEquals("{}", httpClient.getText("optionalToken")); // Optional path token without trailing slash treated as missing
assertEquals("Hello Ratpack", httpClient.getText("greeting/Ratpack")); // Optional path token with value specified
assertEquals("Hello world", httpClient.getText("greeting")); // Optional path token with default handling
assertEquals("Hello UmF0cGFjaw==", httpClient.getText("convert/hex/Ratpack")); // Mandatory path token
assertEquals("3.14159", httpClient.getText("pi")); // Optional regular expression path token with default handling
assertEquals("3.14", httpClient.getText("pi/2")); // Optional regular expression path token with value specified
assertEquals("3.1415927", httpClient.getText("pi/7")); // Optional regular expression path token with value specified
assertEquals("42", httpClient.getText("sum/13/29")); // Mandatory regular expression path tokens
});
}
}
Methods such as get(Handler)
, post(Handler)
etc. bind based on the HTTP method of the request.
They are effectively a combination of the use of path(String, Handler)
and the Context.byMethod(Action)
construct
to declare that the given path ONLY responds to the specified method.
The following two code snippets are identical:
import ratpack.test.embed.EmbeddedApp;
import static org.junit.Assert.*;
public class Example {
public static void main(String... args) throws Exception {
EmbeddedApp.fromHandlers(c -> c
.path("foo", ctx ->
ctx.byMethod(m -> m
.get(() -> ctx.render("ok"))
)
)
).test(httpClient -> {
assertEquals("ok", httpClient.getText("foo"));
assertEquals(405, httpClient.post("foo").getStatusCode());
});
}
}
import ratpack.test.embed.EmbeddedApp;
import static org.junit.Assert.*;
public class Example {
public static void main(String... args) throws Exception {
EmbeddedApp.fromHandlers(c -> c
.get("foo", ctx -> ctx.render("ok"))
).test(httpClient -> {
assertEquals("ok", httpClient.getText("foo"));
assertEquals(405, httpClient.post("foo").getStatusCode());
});
}
}
That is, methods such as get(String, Handler)
, get(Handler)
etc. terminate processing with a
405
(method not supported) client error if the request path matches but the HTTP method does not.
They should not be used for URLs that respond differently depending on the method.
The correct way to do this is to use path(String, Handler)
and Context.byMethod(Action)
.
import ratpack.test.embed.EmbeddedApp;
import static org.junit.Assert.*;
public class Example {
public static void main(String... args) throws Exception {
EmbeddedApp.fromHandlers(c -> c
.path("foo", ctx ->
ctx.byMethod(m -> m
.get(() -> ctx.render("GET"))
.post(() -> ctx.render("POST"))
)
)
).test(httpClient -> {
assertEquals("GET", httpClient.getText("foo"));
assertEquals("POST", httpClient.postText("foo"));
assertEquals(405, httpClient.delete("foo").getStatusCode());
});
}
}
Given the following, a POST to /foo will yield a 405 response.
import ratpack.test.embed.EmbeddedApp;
import static org.junit.Assert.assertEquals;
public class Example {
public static void main(String... args) throws Exception {
EmbeddedApp.fromHandlers(c -> c
.get("foo", ctx -> ctx.render("GET"))
.post("foo", ctx -> ctx.render("POST"))
).test(httpClient -> {
assertEquals("GET", httpClient.getText("foo"));
// NOTE: returns 405, not 200 and "POST"
assertEquals(405, httpClient.post("foo").getStatusCode());
});
}
}
All methods that match HTTP methods, are synonyms for path(String, Class)
in terms of path binding.
That is, get(Handler)
behaves the same way with regard to path binding as path(Handler)
, and not all(Handler)
.
Modifier and Type | Method and Description |
---|---|
default Chain |
all(Class<? extends Handler> handler) |
Chain |
all(Handler handler)
Adds the given handler to this.
|
default Handler |
chain(Action<? super Chain> action)
Constructs a handler using the given action to define a chain.
|
default Handler |
chain(Class<? extends Action<? super Chain>> action) |
default Chain |
delete(Class<? extends Handler> handler) |
default Chain |
delete(Handler handler)
Adds a handler that delegates to the given handler if
the
request HTTPMethod is DELETE and the path is at the current root. |
default Chain |
delete(String path,
Class<? extends Handler> handler) |
default Chain |
delete(String path,
Handler handler)
Adds a handler that delegates to the given handler if
the relative
path matches the given path and the request HTTPMethod
is DELETE . |
default Chain |
files()
files(Action) , using the default config. |
default Chain |
files(Action<? super FileHandlerSpec> config)
Adds a handler that serves files from the file system.
|
default Chain |
fileSystem(String path,
Action<? super Chain> action)
Adds a handler to this chain that changes the
FileSystemBinding for the given handler chain. |
default Chain |
fileSystem(String path,
Class<? extends Action<? super Chain>> action) |
default Chain |
get(Class<? extends Handler> handler) |
default Chain |
get(Handler handler)
Adds a handler that delegates to the given handler
if the
request HTTPMethod is GET and the path is at the
current root. |
default Chain |
get(String path,
Class<? extends Handler> handler) |
default Chain |
get(String path,
Handler handler)
Adds a handler that delegates to the given handler
if the relative
path matches the given path and the request
HTTPMethod is GET . |
Registry |
getRegistry()
The registry that backs this chain.
|
ServerConfig |
getServerConfig()
The server config of the application that this chain is being created for.
|
default Chain |
host(String hostName,
Action<? super Chain> action)
Adds a handler to the chain that delegates to the given handler chain if the request has a
Host header that matches the given value exactly. |
default Chain |
host(String hostName,
Class<? extends Action<? super Chain>> action) |
default Chain |
insert(Action<? super Chain> action)
Inserts the given nested handler chain.
|
default Chain |
insert(Class<? extends Action<? super Chain>> action) |
default Chain |
notFound()
Raises a 404
Context.clientError(int) . |
default Chain |
onlyIf(Predicate<? super Context> test,
Class<? extends Handler> handler) |
default Chain |
onlyIf(Predicate<? super Context> test,
Handler handler)
Invokes the given handler only if the predicate passes.
|
default Chain |
options(Class<? extends Handler> handler) |
default Chain |
options(Handler handler)
Adds a handler that delegates to the given handler if
the
request HTTPMethod is OPTIONS and the path is at the current root. |
default Chain |
options(String path,
Class<? extends Handler> handler) |
default Chain |
options(String path,
Handler handler)
Adds a handler that delegates to the given handler if
the relative
path matches the given path and the request HTTPMethod
is OPTIONS . |
default Chain |
patch(Class<? extends Handler> handler) |
default Chain |
patch(Handler handler)
Adds a handler that delegates to the given handler if
the
request HTTPMethod is PATCH and the path is at the current root. |
default Chain |
patch(String path,
Class<? extends Handler> handler) |
default Chain |
patch(String path,
Handler handler)
Adds a handler that delegates to the given handler if
the relative
path matches the given path and the request HTTPMethod
is PATCH . |
default Chain |
path(Class<? extends Handler> handler) |
default Chain |
path(Handler handler) |
default Chain |
path(String path,
Class<? extends Handler> handler) |
default Chain |
path(String path,
Handler handler)
Adds a handler that delegates to the given handler if the relative
path
matches the given path exactly. |
default Chain |
post(Class<? extends Handler> handler) |
default Chain |
post(Handler handler)
Adds a handler that delegates to the given handler if
the
request HTTPMethod is POST and the path is at the current root. |
default Chain |
post(String path,
Class<? extends Handler> handler) |
default Chain |
post(String path,
Handler handler)
Adds a handler that delegates to the given handler if
the relative
path matches the given path and the request HTTPMethod
is POST . |
default Chain |
prefix(String prefix,
Action<? super Chain> action)
Adds a handler that delegates to the given handlers if the
relative path starts with the given
prefix . |
default Chain |
prefix(String prefix,
Class<? extends Action<? super Chain>> action) |
default Chain |
put(Class<? extends Handler> handler) |
default Chain |
put(Handler handler)
Adds a handler that delegates to the given handler if
the
request HTTPMethod is PUT and the path is at the current root. |
default Chain |
put(String path,
Class<? extends Handler> handler) |
default Chain |
put(String path,
Handler handler)
Adds a handler that delegates to the given handler if
the relative
path matches the given path and the request HTTPMethod
is PUT . |
default Chain |
redirect(int code,
String location)
Sends an HTTP redirect to the specified location.
|
default Chain |
register(Action<? super RegistrySpec> action)
Builds a new registry via the given action, then registers it via
register(Registry) . |
default Chain |
register(Action<? super RegistrySpec> registryAction,
Action<? super Chain> action)
Adds a handler that inserts the given handler chain with a registry built by the given action via
Context.insert(ratpack.registry.Registry, Handler...) . |
default Chain |
register(Action<? super RegistrySpec> registryAction,
Class<? extends Action<? super Chain>> action) |
default Chain |
register(Registry registry)
Makes the contents of the given registry available for downstream handlers of the same nesting level.
|
default Chain |
register(Registry registry,
Action<? super Chain> action)
Adds a handler that inserts the given handler chain with the given registry via
Context.insert(ratpack.registry.Registry, Handler...) . |
default Chain |
register(Registry registry,
Class<? extends Action<? super Chain>> action) |
default Chain |
when(boolean test,
Action<? super Chain> action)
Inlines the given chain if
test is true . |
default Chain |
when(boolean test,
Class<? extends Action<? super Chain>> action)
Inlines the given chain if
test is true . |
default Chain |
when(Predicate<? super Context> test,
Action<? super Chain> action) |
default Chain |
when(Predicate<? super Context> test,
Class<? extends Action<? super Chain>> action) |
default Chain files(Action<? super FileHandlerSpec> config) throws Exception
The given action configures how and what files will be served.
The handler binds to a request path
and a directory
within the current filesystem binding.
The portion of the request path past the path binding identifies the target file within the directory.
import ratpack.test.embed.EphemeralBaseDir;
import ratpack.test.embed.EmbeddedApp;
import static org.junit.Assert.assertEquals;
public class Example {
public static void main(String... args) throws Exception {
EphemeralBaseDir.tmpDir().use(baseDir -> {
baseDir.write("public/some.text", "foo");
baseDir.write("public/index.html", "bar");
EmbeddedApp.of(s -> s
.serverConfig(c -> c.baseDir(baseDir.getRoot()))
.handlers(c -> c
.files(f -> f.dir("public").indexFiles("index.html"))
)
).test(httpClient -> {
assertEquals("foo", httpClient.getText("some.text"));
assertEquals("bar", httpClient.getText());
assertEquals(404, httpClient.get("no-file-here").getStatusCode());
});
});
}
}
config
- the file handler configurationthis
Exception
- any thrown by config
Handlers.files(ServerConfig, Action)
,
FileHandlerSpec
default Chain files()
files(Action)
, using the default config.this
default Handler chain(Action<? super Chain> action) throws Exception
action
- The action that defines the all chainException
- any thrown by action
default Handler chain(Class<? extends Action<? super Chain>> action) throws Exception
Exception
default Chain delete(String path, Handler handler)
path
matches the given path
and the request
HTTPMethod
is DELETE
.path
- the relative path to match onhandler
- the handler to delegate toget(String, Handler)
,
post(String, Handler)
,
put(String, Handler)
,
patch(String, Handler)
,
path(String, Handler)
default Chain delete(Handler handler)
request
HTTPMethod
is DELETE
and the path
is at the current root.handler
- the handler to delegate toget(Handler)
,
post(Handler)
,
put(Handler)
,
patch(Handler)
default Chain fileSystem(String path, Action<? super Chain> action) throws Exception
FileSystemBinding
for the given handler chain.path
- the relative path to the new file system binding pointaction
- the definition of the all chainException
- any thrown by action
default Chain fileSystem(String path, Class<? extends Action<? super Chain>> action) throws Exception
Exception
default Chain get(String path, Handler handler)
path
matches the given path
and the request
HTTPMethod
is GET
.
path
- the relative path to match onhandler
- the handler to delegate topost(String, Handler)
,
put(String, Handler)
,
patch(String, Handler)
,
delete(String, Handler)
,
path(String, Handler)
default Chain get(Handler handler)
request
HTTPMethod
is GET
and the path
is at the
current root.handler
- the handler to delegate topost(Handler)
,
put(Handler)
,
patch(Handler)
,
delete(Handler)
ServerConfig getServerConfig()
Registry getRegistry() throws IllegalStateException
What the registry is depends on how the chain was created.
The Handlers.chain(ServerConfig, Registry, Action)
allows the registry to be specified.
For a Guice based application, the registry is backed by Guice.
IllegalStateException
- if there is no backing registry for this chainHandlers.chain(ServerConfig, Registry, Action)
Chain all(Handler handler)
handler
- the handler to adddefault Chain path(String path, Handler handler)
path
matches the given path
exactly.
Nesting path
handlers will not work due to the exact matching, use a combination of path
and prefix
instead. See prefix(String, ratpack.func.Action)
for details.
// this will not work path("person/:id") { path("child/:childId") { // a request of /person/2/child/1 will not get passed the first all as it will try // to match "person/2/child/1" with "person/2" which does not match } // this will work prefix("person/:id") { path("child/:childId") { // a request of /person/2/child/1 will work this time } }
See Handlers.path(String, Handler)
for the details on how path
is interpreted.
path
- the relative path to match exactly onhandler
- the handler to delegate topost(String, Handler)
,
get(String, Handler)
,
put(String, Handler)
,
patch(String, Handler)
,
delete(String, Handler)
default Chain host(String hostName, Action<? super Chain> action) throws Exception
Host
header that matches the given value exactly.
chain.
host("foo.com", new Action<Chain>() {
public void execute(Chain hostChain) {
hostChain.all(new Handler() {
public void handle(Context context) {
context.getResponse().send("Host Handler");
}
});
}
});
hostName
- the name of the HTTP Header to match onaction
- the handler chain to delegate to if the host matchesException
- any thrown by action
default Chain host(String hostName, Class<? extends Action<? super Chain>> action) throws Exception
Exception
default Chain insert(Action<? super Chain> action) throws Exception
Shorter form of all(Handler)
handler}(chain
(action
).
action
- the handler chain to insertException
- any thrown by action
default Chain insert(Class<? extends Action<? super Chain>> action) throws Exception
Exception
default Chain patch(String path, Handler handler)
path
matches the given path
and the request
HTTPMethod
is PATCH
.path
- the relative path to match onhandler
- the handler to delegate toget(String, Handler)
,
post(String, Handler)
,
put(String, Handler)
,
delete(String, Handler)
,
path(String, Handler)
default Chain patch(Handler handler)
request
HTTPMethod
is PATCH
and the path
is at the current root.handler
- the handler to delegate toget(Handler)
,
post(Handler)
,
put(Handler)
,
delete(Handler)
default Chain options(String path, Handler handler)
path
matches the given path
and the request
HTTPMethod
is OPTIONS
.path
- the relative path to match onhandler
- the handler to delegate toget(String, Handler)
,
post(String, Handler)
,
put(String, Handler)
,
delete(String, Handler)
,
path(String, Handler)
default Chain options(String path, Class<? extends Handler> handler)
path
- the path to bind tohandler
- a handlerthis
default Chain options(Handler handler)
request
HTTPMethod
is OPTIONS
and the path
is at the current root.handler
- the handler to delegate toget(Handler)
,
post(Handler)
,
put(Handler)
,
delete(Handler)
default Chain options(Class<? extends Handler> handler)
handler
- a handlerdefault Chain post(String path, Handler handler)
path
matches the given path
and the request
HTTPMethod
is POST
.
path
- the relative path to match onhandler
- the handler to delegate toget(String, Handler)
,
put(String, Handler)
,
patch(String, Handler)
,
delete(String, Handler)
,
path(String, Handler)
default Chain post(Handler handler)
request
HTTPMethod
is POST
and the path
is at the current root.
handler
- the handler to delegate toget(Handler)
,
put(Handler)
,
patch(Handler)
,
delete(Handler)
default Chain prefix(String prefix, Action<? super Chain> action) throws Exception
prefix
.
All path based handlers become relative to the given prefix
.
chain
.prefix("person/:id", new Action<Chain>() {
public void execute(Chain personChain) throws Exception {
personChain
.get("info", new Handler() {
public void handle(Context context) {
// e.g. /person/2/info
}
})
.post("save", new Handler() {
public void handle(Context context) {
// e.g. /person/2/save
}
})
.prefix("child/:childId", new Action<Chain>() {
public void execute(Chain childChain) {
childChain
.get("info", new Handler() {
public void handle(Context context) {
// e.g. /person/2/child/1/info
}
});
}
});
}
});
See Handlers.prefix(String, Handler)
for format details on the prefix
string.
prefix
- the relative path to match onaction
- the handler chain to delegate to if the prefix matchesException
- any thrown by action
default Chain prefix(String prefix, Class<? extends Action<? super Chain>> action) throws Exception
Exception
default Chain put(String path, Handler handler)
path
matches the given path
and the request
HTTPMethod
is PUT
.path
- the relative path to match onhandler
- the handler to delegate toget(String, Handler)
,
post(String, Handler)
,
patch(String, Handler)
,
delete(String, Handler)
,
path(String, Handler)
default Chain put(Handler handler)
request
HTTPMethod
is PUT
and the path
is at the current root.handler
- the handler to delegate toget(Handler)
,
post(Handler)
,
patch(Handler)
,
delete(Handler)
default Chain redirect(int code, String location)
The handler to add is created via Handlers.redirect(int, String)
.
code
- the 3XX HTTP status code.location
- the URL to set in the Location response headerHandlers.redirect(int, String)
default Chain register(Registry registry)
The registry is inserted via the Context.next(Registry)
method.
registry
- the registry whose contents should be made available to downstream handlersdefault Chain register(Action<? super RegistrySpec> action) throws Exception
register(Registry)
.action
- the definition of a registryException
- any thrown by action
default Chain register(Registry registry, Action<? super Chain> action) throws Exception
Context.insert(ratpack.registry.Registry, Handler...)
.registry
- the registry to insertaction
- the definition of the handler chainException
- any thrown by action
default Chain register(Registry registry, Class<? extends Action<? super Chain>> action) throws Exception
Exception
default Chain register(Action<? super RegistrySpec> registryAction, Action<? super Chain> action) throws Exception
Context.insert(ratpack.registry.Registry, Handler...)
.registryAction
- the definition of the registry to insert]action
- the definition of the handler chainException
- any thrown by action
default Chain register(Action<? super RegistrySpec> registryAction, Class<? extends Action<? super Chain>> action) throws Exception
Exception
default Chain when(Predicate<? super Context> test, Action<? super Chain> action) throws Exception
Exception
default Chain when(Predicate<? super Context> test, Class<? extends Action<? super Chain>> action) throws Exception
Exception
default Chain when(boolean test, Action<? super Chain> action) throws Exception
test
is true
.
This is literally just sugar for wrapping the given action in an if
statement.
It can be useful when conditionally adding handlers based on state available when building the chain.
import ratpack.test.embed.EmbeddedApp;
import static org.junit.Assert.assertEquals;
public class Example {
public static void main(String... args) throws Exception {
EmbeddedApp.of(a -> a
.registryOf(r -> r.add(1))
.handlers(c -> c
.when(c.getRegistry().get(Integer.class) == 0, i -> i
.get(ctx -> ctx.render("ok"))
)
)
).test(httpClient ->
assertEquals(httpClient.get().getStatusCode(), 404)
);
EmbeddedApp.of(a -> a
.registryOf(r -> r.add(0))
.handlers(c -> c
.when(c.getRegistry().get(Integer.class) == 0, i -> i
.get(ctx -> ctx.render("ok"))
)
)
).test(httpClient ->
assertEquals(httpClient.getText(), "ok")
);
}
}
test
- whether to include the given chain actionaction
- the chain action to maybe includeException
- any thrown by action
default Chain when(boolean test, Class<? extends Action<? super Chain>> action) throws Exception
test
is true
.
Similar to when(boolean, Action)
, except obtains the action instance from the registry by the given type.
test
- whether to include the given chain actionaction
- the chain action to maybe includeException
- any thrown by action
default Chain onlyIf(Predicate<? super Context> test, Handler handler)
This method differs from when()
in that it does not insert the handler;
but directly calls its Handler.handle(Context)
method.
test
- the predicatehandler
- the handlerthis
default Chain notFound()
Context.clientError(int)
.
This can be used to effectively terminate processing early. This is sometimes useful when using a scoped client error handler.
import ratpack.error.ClientErrorHandler;
import ratpack.test.embed.EmbeddedApp;
import static org.junit.Assert.assertEquals;
public class Example {
public static void main(String... args) throws Exception {
EmbeddedApp.of(s -> s
.registryOf(r -> r
.add(ClientErrorHandler.class, (ctx, code) -> ctx.render("global"))
)
.handlers(c -> c
.prefix("api", api -> api
.register(r -> r.add(ClientErrorHandler.class, (ctx, code) -> ctx.render("scoped")))
.get("foo", ctx -> ctx.render("foo"))
.notFound()
)
)
).test(http -> {
assertEquals(http.getText("not-there"), "global");
assertEquals(http.getText("api/foo"), "foo");
assertEquals(http.getText("api/not-there"), "scoped");
});
}
}
this