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

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

There is a newer version: 2.2.0
Show newest version
{#==========================================
Docs : "Quick Tutorial"
==========================================#}

Quick Tutorial

Here, we'll present a quick tutorial on how to develop a Spincast application : as a traditional website or as a SPA application. We won't go into too much details so, to dig deeper, have a look at :

  • The dedicated Demos/Tutorials section of the site.
  • The Quick Start application, which is a fully working Spincast application.
  • The others sections of this documentation!

{#========================================== Section "Quick Tutorial / Traditional website" ==========================================#}

1. Traditional website

A "traditional website" is a web application where the server generates HTML pages, using a Templating Engine. This is different from the more recent SPA approach, where the interface is generated client side (using javascript) and where the backend only provides REST services (by returning Json or, more rarely these days, XML).

1.1. Bootstrapping

Bootstrapping a Spincast application involves 3 main steps :

  • Using the Bootstrapper to initialize your application. This is where you specify the components to bind and the plugins to install in order to create the Guice context for your application.
  • Defining Routes and Route Handlers. We're going to see those in a minute.
  • Starting the HTTP Server.
Here's a quick example of using the bootstrapper :

Spincast.configure()
        .module(new AppModule())
        .init(args);

Please read the whole section dedicated to bootstrapping for more information about this topic.

The quickest way to start a Spincast application is to download the Quick Start application and to adapt it to your needs.

1.2. Defining Routes

You define some Routes and you specify which Route Handlers should handle them. The Route Handlers are often methods in a controller but can also be defined inline, directly in the Route definitions.

The Routes definitions can be all grouped together in a dedicated class or can be defined in controllers (have a look at The Router is dynamic for an example).

You can learn more about the various routing options in the Routing section, but here's a quick example of Route definitions :

// For a GET request. Uses a method reference
// to target a controller method as the Route Handler :
router.GET("/books/${bookId}").handle(bookController::booksGet);
       
// For any HTTP request. Uses an inline Route Handler :
router.ALL("/hello").handle(context -> context.response().sendPlainText("Hello!"));

1.3. Route Handlers

Most of the time, a Route Handler is implemented as a method in a controller. It receives a Request Context object as a parameter. This Request Context is extensible and is one of the most interesting parts of Spincast! In this quick example, we simply use the default Request Context implementation, "DefaultRequestContext" :

public class BookController {

    // Route Handler dedicated to handle GET requests
    // for a book : "/books/${bookId}"
    public void booksGet(DefaultRequestContext context) {
        // ...
    }
}

1.4. Getting information about the request

In your Route Handlers, you use the Request Context object and its various add-ons to get the information you need about the current request :

public void booksGet(DefaultRequestContext context) {

    // Path parameter
    // From "/books/${bookId}" for example
    String bookId = context.request().getPathParam("bookId");

    // QueryString parameter
    String page = context.request().getQueryStringParamFirst("page");
    
    // Field received from a POSTed form
    String newTitle = context.request().getFormData().getString("newTitle");

    // HTTP Header
    String authorizationHeader = context.request().getHeaderFirst("Authorization");

    // Cookie
    String localeCookieValue = context.request().getCookie("locale");

    //...
}

1.5. Building the response's model

You process the current request using any business logic you need, and you build the model for the response. This response model is a JsonObject accessible via "context.response().getModel()" : it is the object where you store all the information you want to return as the response.

You may add to this response model the variables you want your templates to have access to :

public void booksGet(DefaultRequestContext context) {
    
    //...
    
    JsonObject book = context.json().create();
    book.set("author", "Douglas Adams");
    book.set("title", "The Hitchhiker's Guide to the Galaxy");
    
    // Adds the book to the response model
    context.response().getModel().set("book", book);
    
    //...
}

1.6. Rendering the response model using a template

When you develop a traditional website, you usually want to render a template so HTML is going to be displayed. To do so, you use the integrated Templating Engine :

public void booksGet(DefaultRequestContext context) {
    
    //... builds the response model
    
    // Sends the response model as HTML, using a template
    context.response().sendTemplateHtml("/templates/book.html");
}

1.7. Writing the template

Here is a template example using the syntax of the default Templating Engine, Pebble. Notice that the variables we added to the response model are available.

{% verbatim %}

{% if book is not empty %}
    <div class="book">
        <h2>{{book.title}}</h2>
        <p>Author : {{book.author}}</p>
    </div>
{% else %}
    <div>
        Book not found!
    </div>
{% endif %}
{% endverbatim %}

{#========================================== Section "Quick Tutorial / SPA website" ==========================================#}

2. SPA / REST services

The main difference between a SPA application (or a set of plain REST services) and a traditional website, is that in a SPA you don't generate HTML server side. Instead, most of the logic is client-side, and your Spincast application only acts as a provider of REST services to which your client-side application talks using Json or, more rarely these days, XML.

2.1. Bootstrapping

Bootstrapping a Spincast application involves 3 main steps :

  • Using the Bootstrapper to initialize your application. This is where you specify the components to bind and the plugins to install in order to create the Guice context for your application.
  • Defining Routes and Route Handlers. We're going to see those in a minute.
  • Starting the HTTP Server.
Here's a quick example of using the bootstrapper :

Spincast.configure()
        .module(new AppModule())
        .init(args);

Please read the whole section dedicated to bootstrapping for more information about this topic.

The quickest way to start a Spincast application is to download the Quick Start application and to adapt it to your needs.

2.2. Defining Routes

You define some Routes and you specify which Route Handlers should handle them. The Route Handlers are often methods in a controller but can also be defined inline, directly on the Route definitions.

The Routes definitions can be all grouped together in a dedicated class or can be defined in controllers (have a look at The Router is dynamic for an example).

In general, if you are building a SPA, you want to return a single HTML page : that index page is going to load .js files and, using those, will bootstrap your client-side application. Using Spincast, you can return that index page as a Static Resource, or you can generate it using a template. Let's first see how you could return the index page as a Static Resource :

// The static "index.html" page that is going to bootstrap
// our SPA
router.file("/").classpath("/index.html").handle();

// The resources (.js, .css, images, etc.) will 
// be located under the "/public" path :
router.dir("/public").classpath("/myResources").handle();

// ... the REST endpoints routes

As you can see, Spincast will return the "index.html" file when a "/" request is made. In this HTML page, you are going to load all the required resources (mostly .js files first), and bootstrap your whole application.

You can also use a template to generate the first index page. This allows you to dynamically tweak it, to use variables. Here's an example :

// Inline Route Handler that evaluates
// a template to generate the HTML index page.
router.GET("/").handle(context -> {
    
    // Adds some variables to the response model so
    // the template has access to them.
    context.response().getModel().set("randomQuote", getRandomQuote());
    
    // Renders the template
    context.response().sendTemplateHtml("/index.html"); 
});

// The resources (.js, .css, images, etc.) will 
// be located under the "/public" path :
router.dir("/public").classpath("/public").handle();

// ... the REST endpoints routes

By using such template to send your index page, you have access to all the functionalities provided by the Templating Engine. Note that if your template is quite complexe, you're probably better creating a controller to define the Route Handler, instead of defining it inline like in our example!

Once the Route for the index page and those for the resources are in place, you add the ones required for your REST endpoints. For example :

// Endpoint to get a book
router.GET("/books/${bookId}").handle(bookController::booksGet);

// Endpoint to modify a book
router.POST("/books/${bookId}").handle(bookController::booksModify);
        
// ...

2.3. Route Handlers

Most of the time, a Route Handler is implemented as a method in a controller. It receives a Request Context object as a parameter. This Request Context is extensible and is one of the most interesting parts of Spincast! In this quick example, we simply use the default Request Context implementation, "DefaultRequestContext" :

public class BookController {

    // Route Handler dedicated to handle GET requests
    // for a book : "/books/${bookId}"
    public void booksGet(DefaultRequestContext context) {
        // ...
    }
}

2.4. Getting information about the request

In your Route Handlers, you use the Request Context object and its various add-ons to get the information you need about the current request (an AJAX request for example) :

public void booksGet(DefaultRequestContext context) {

    // The Json body of the request as a JsonObject
    JsonObject jsonObj = context.request().getJsonBody();

    // Path parameter
    // From "/books/${bookId}" for example
    String bookId = context.request().getPathParam("bookId");

    // HTTP Header
    String authorizationHeader = context.request().getHeaderFirst("Authorization");

    // Cookie
    String localeCookieValue = context.request().getCookie("locale");

    //...
}

Very often in a SPA application, or when you develop plain REST services, you are going to receive a Json object as the body of a request (with a "application/json" content-type). In the previous code snippet, context.request().getJsonBody() gets that Json from the request and creates a JsonObject from it so it is easy to manipulate.

2.5. Creating and sending a Json / XML response

When you receive a request, you process it using any required business logic, and you then build the Json (or XML) object to return as a response. There are two ways to achieve that. The prefered approach, is to create a typed object, a book created from a Book class for example, and explicitly send this entity as Json. For example :

public void booksGet(DefaultRequestContext context) {

    String bookId = context.request().getPathParam("bookId");
    Book someBook = getBook(bookId);
    
    context.response().sendJson(someBook);
}

The second option, probably more useful for traditional websites though, is to use the response model to dynamically create the Json object to send.

You get the response model as a JsonObject by calling the context.response().getModel() method, you add elements to it and you send it as Json :

public void booksGet(DefaultRequestContext context) {

    // Gets the response model
    JsonObject responseModel = context.response().getModel();

    // Gets a book
    String bookId = context.request().getPathParam("bookId");
    Book someBook = getBook(bookId);

    // Adds the book to the response model, using
    // the "data.book" key
    responseModel.set("data.book", book);

    // Adds a "code" element to the response model
    responseModel.set("code", AppCode.APP_CODE_ACCEPTED);

    // Adds a timestamp to the response model
    responseModel.set("timestamp", new Date());
    
    // This is going to send the response model as Json
    context.response().sendJson();
}

In this example, the generated Json response would have a "application/json" content-type and would look like this :

{
    "code" : 12345,
    "timestamp" : "2016-11-06T22:58+0000",
    "data" : {
        "book" : {
            "author" : "Douglas Adams",
            "title" : "The Hitchhiker's Guide to the Galaxy"
        }
    }
}

2.6. Consuming a Json / XML response

You consume the Json response from your client-side SPA application whatever it is built with : Angular, React, Vue.js, Ember, etc. Of course, we won't go into details here since there are so many client-side frameworks!

A Json response can also be consumed by a client which is not a SPA : it can be a response for a Ajax request made using Jquery or plain javascript. Such Json response can also be consumed by a backend application able to send HTTP requests.





© 2015 - 2024 Weber Informatics LLC | Privacy Policy