
templates.docs.sendingResponse.html Maven / Gradle / Ivy
Show all versions of spincast-website Show documentation
{#==========================================
Docs : "Sending the response"
==========================================#}
Sending the response
The kind of responses you send to incoming requests really depends on the type of
application you're building! If you are building a traditional website, you will
most of the time use the integrated Templating Engine
to output HTML
as the response to a request.
But if you are building a SPA
, or if you use Spincast for
REST
microservices/services, then your responses will
probably be Json
or XML
objects.
{#==========================================
Section "Sending the response / The response model"
==========================================#}
The response model object
Inside a Route Handler
, you can (but are not forced to) use the
provided response model
as an easy way to build the response. This
can be useful to build a response to be sent as Json
, but is
mainly use to accumulate the various parameters required to render a template.
You get this model by using the getModel()
method on the response()
add-on :
public void myRouteHandler(DefaultRequestContext context) {
JsonObject responseModel = context.response().getModel();
// ... adds elements to this response model
// ... then sends the response
}
The response model is a
JsonObject so it can be manipulated as such!
You can add any type of element on it. When the added object is not
of a type native to JsonObjects
, the object is converted
to a JsonObject
or to a JsonArray
.
You can use the json()
add-on to create new
JsonObject
and JsonArray
elements to be added to the response model.
For example, let's add to the response model : a simple String variable, a Book object
and a JsonObject
representing a user...
public void myRouteHandler(DefaultRequestContext context) {
JsonObject responseModel = context.response().getModel();
// Adds a simple String variable
responseModel.set("simpleVar", "test");
// Adds a Book : this object will automatically
// be converted to a JsonObject
Book book = getBook(42);
responseModel.set("myBook", book);
// Then adds a JsonObject representing a user
JsonObject user = context.json().create();
user.set("name", "Stromgol");
user.set("age", 30);
responseModel.set("user", user);
// ...
}
At this point, the response model would be something like :
{
"simpleVar": "test",
"myBook": {
"id": 42,
"title": "The Hitchhiker's Guide to the Galaxy",
"author": "Douglas Adams"
},
"user": {
"name": "Stromgol",
"age": 30
}
}
To resume : you use any business logic required to process a request, you query
some data sources if needed, then you build the response model. When the response model is
ready, you decide how to send it. Let's see the different options...
{#==========================================
Section "Sending the response / sending the model as HTML, using a template"
==========================================#}
Sending the response model as HTML
, using a template
If you're building a traditional website, you will most of the time send HTML
as the response for a request. To do so, you can use the Templating Engine,
and specify which template to use to render the data contained in the response model :
public void myRouteHandler(DefaultRequestContext context) {
JsonObject responseModel = context.response().getModel();
// ... adds variables to the response model
// Renders the response model using a template
context.response().sendTemplateHtml("/templates/myTemplate.html");
}
The default templating engine is Pebble. The
template files are found on the classpath by default, but there are overload methods to find
them on the file system too. Learn more about that in the
Templating Engine section.
{#==========================================
Section "Sending the response / Sending the model as Json or XML
==========================================#}
Sending Json
or XML
If you are using Spincast to build a Single Page Application
or REST services
,
you will probably want to directly return a Json
(or as XML
) object instead of rendering an HTML
template.
Most of the time you are going to return that resource directly.
Here's an example :
public void booksGet(DefaultRequestContext context) {
String bookId = context.request().getPathParam("bookId");
Book someBook = getBook(bookId);
// Sends the book as Json
context.response().sendJson(someBook);
// ... or as XML
context.response().sendXML(someBook);
}
By using the
sendJson(someBook)
method, the book object will
automatically be serialized to Json
and sent using the
appropriated "application/json"
content-type.
In some cases, it may be useful to build the object to return using the
response model
, exactly as you may do when developing a traditional website.
This approach is discussed in the
SPA Quick Tutorial.
Here's an example :
public void myRouteHandler(DefaultRequestContext context) {
JsonObject responseModel = context.response().getModel();
JsonObject user = context.json().create();
user.set("name", "Stromgol");
user.set("age", 42);
responseModel.set("user", user);
// This will send the response model as "application/json" :
// {"user":{"name":"Stromgol","age":42}}
context.response().sendJson();
// or, this will send the response model as "application/xml" :
// <JsonObject><user><name>Stromgol</name><age>42</age></user></JsonObject>
context.response().sendXml();
}
The sendJson()
method, without any argument, takes the response model,
converts it to a Json
string and sends it with the appropriate
"application/json"
content-type.
{#==========================================
Section "Sending the response / sending a specific object"
==========================================#}
Sending specific content
You can use the default response model
to build the object which will be used
for the response, but you can also send any object directly. We already
saw that we can send an object using the sendJson(myObject)
method, but
Spincast provides other options. You can...
-
Send
characters
, using the content-type of your choice :
public void myRouteHandler(DefaultRequestContext context) {
// Sends as "text/plain"
context.response().sendPlainText("This is plain text");
// Sends as "application/json"
context.response().sendJson("{\"name\":\"Stromgol\"}");
// Sends as "application/xml"
context.response().sendXml("<root><name>Stromgol</name></root>");
// Sends as "text/html"
context.response().sendHtml("<h1>Hi Stromgol!</h1>");
// Sends using a specified content-type
context.response().sendCharacters("<italic>Stromgol!</italic>", "text/richtext");
}
-
Evaluate a template by yourself and send it as
HTML
,
explicitly :
public void myRouteHandler(DefaultRequestContext context) {
Map<String, Object> params = getTemplateParams();
String result = context.templating().evaluate("/templates/myTemplate.html", params);
// Sends the evaluated template
context.response().sendHtml(result);
}
-
Send a specific object as
Json
or as XML
:
public void myRouteHandler(DefaultRequestContext context) {
User user = getUserService().getUser(123);
// Sends the user object as Json
context.response().sendJson(user);
// or, sends it as XML
context.response().sendXml(user);
}
-
Send binary data :
public void myRouteHandler(DefaultRequestContext context) {
byte[] imageBytes = loadImageBytes();
// Sends as "application/octet-stream"
context.response().sendBytes(imageBytes);
// or sends using a specific content-type
context.response().sendBytes(imageBytes, "image/png");
}
{#==========================================
Section "Sending the response / Redirecting"
==========================================#}
Redirecting
Sometimes you need to redirect a request to a new page. There are multiple cases
where that can be useful. For example when you decide to change a URL in your application,
but don't want existing links pointing to the old URL to break. In that particular case you can
use using redirection rules :
the requests for the old URL won't even reach any route handler... A redirection header
will be sent at the very beginning of the routing process.
Another case where a redirection is useful is when you are building a traditional website
and a form is submitted via a POST
method. In that case, it is seen as a good practice
to redirect to a confirmation page once the form has been validated
successfully. By doing so, the form won't be submitted again if the user decides to refresh
the resulting page.
Other than redirection rules
, there
are two ways of redirecting a request to a new page :
-
By using the "redirect(...)"
method on the response()
add-on, in a Route Handler
:
public void myRouteHandler(DefaultRequestContext context) {
context.response().redirect("/new-url");
}
Calling this redirect(...)
method simply adds redirection headers to the response,
it doesn't send anything. This means that any remaining
Route Handlers
/Filters
will be ran as usual
and could even, eventually, remove the redirection headers that the method added.
-
By throwing a RedirectException exception.
public void myRouteHandler(DefaultRequestContext context) {
// Any remaing filters will be skipped
throw new RedirectException("/new-url");
}
Unlike the redirect(...)
method approach, throwing a RedirectException
will end the current routing process and immediately send the redirection
headers. Only the remaining after Filters will be run, any other remaining handler
will be skipped.
The URL parameter of a redirection can :
-
Be absolute or relative.
-
Be empty. In that case, the request will be redirected to the current URL.
-
Start with
"?"
. In that case, the current URL will be used but with
the specified queryString.
-
Start with
"#"
. In that case, the current URL will be used but with
the specified anchor.
Other redirections options :
-
You can specify if the redirection should be permanent (
301
)
or temporary (302
). The default is "temporary".
-
You can specify a Flash message :
public void myRouteHandler(DefaultRequestContext context) {
// Sends a permanent redirection (301) with
// a Flash message to be displayed on the target page
context.response().redirect("/new-url",
true,
FlashMessageLevel.WARNING,
"This is a warning message!");
}
{#==========================================
Section "Sending the response / Forwarding"
==========================================#}
Forwarding
Forwarding the request doesn't send anything, it's only a way of
changing the current route. By forwarding a request, you restart the
routing process from scratch,
this time using a new, specified route instead of the original one.
Forwarding is very different than
Redirecting since
the client can't know that the request endpoint has been changed...
The process is entirely server side.
Since forwarding the request ends the current routing process and skips any
remaining Route Handlers
/Filters
, it is done by throwing an exception,
ForwardRouteException :
public void myRouteHandler(DefaultRequestContext context) {
throw new ForwardRouteException("new-url");
}
{#==========================================
Section "Sending the response / Flushing"
==========================================#}
Flushing the response
Flushing the response consists in sending the HTTP headers
and any data already added to the response buffer. You only start to actually send
something to the user when the response is flushed!
It is important to know that the first time the response is flushed,
the HTTP headers are sent and therefore can't be modified
anymore. Indeed, the HTTP headers are only sent once, during the first flush
of the response.
Note that explicitly flushing the response is not required : this is automatically done
when the routing process is over. In fact, you don't need to explicitly flush the response
most of the time. But there are some few cases where you may need to do so, for example for the user starts receiving
data even if you are still collecting more of it on the server.
So, how do you flush the response? The first option is by using the dedicated
flush()
method :
public void myRouteHandler(DefaultRequestContext context) {
context.response().flush();
}
A second option is to use the "flush"
parameter available
on many sendXXX(...)
methods of the response()
add-on. For example...
public void myRouteHandler(DefaultRequestContext context) {
// true => flushes the response
context.response().sendPlainText("Hello world!", true);
}
Note that flushing the response
doesn't prevent any remaining Route Handlers
/Filters
to be run, it simply
send the response as it currently is.
Finally, note that you can also use the end()
method
of the response() add-on if you want the response to be flushed and be closed. In that case,
remaining Route Handlers
/Filters
will still run,
but they won't be able to send any more data :
public void myRouteHandler(DefaultRequestContext context) {
context.response().end();
}
{#==========================================
Section "Sending the response / Skipping remaining handlers"
==========================================#}
Skipping remaining handlers
Most of the time you want to allow the main Route Handler
and all its associated filters to be run. A filter may modify some headers, may
log some information, etc. But in the rare cases where you want to make sure the response
is sent as is and that anything else is skipped, you can throw a
SkipRemainingHandlersException.
public void myRouteHandler(DefaultRequestContext context) {
context.response().sendPlainText("Hello world!");
throw new SkipRemainingHandlersException();
}
Unlike simply flushing and ending the response (using the end()
method),
throwing a SkipRemainingHandlersException
skips any remaining handlers : the
response will be sent as is, and the routing process will be over. This means that
even the after filters will be skipped!