All Downloads are FREE. Search and download functionalities are using the official Maven repository.

templates.docs.sendingResponse.html Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
{#==========================================
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!





© 2015 - 2024 Weber Informatics LLC | Privacy Policy