Renarde  Web Framework - Main Concepts
 Web Framework - Main Concepts
Models
By convention, you can place your model classes in the model package, but anywhere else works just as well.
We recommend using Hibernate ORM with Panache.
Here’s an example entity for our sample Todo application:
package model;
import java.util.Date;
import java.util.List;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
@Entity
public class Todo extends PanacheEntity {
    @ManyToOne
    public User owner;
    public String task;
    public boolean done;
    public Date doneDate;
    public static List<Todo> findByOwner(User user) {
        return find("owner = ?1 ORDER BY id", user).list();
    }
}Controllers
By convention, you can place your controllers in the rest package, but anywhere else works just as well.
You have to extend the Controller class in order to benefit from extra easy endpoint declarations and reverse-routing, but that superclass also gives you useful methods.
We usually have one controller per model class, so we tend to use the plural entity name for the corresponding controller:
package rest;
import java.util.Date;
import java.util.List;
import jakarta.validation.constraints.NotBlank;
import jakarta.ws.rs.POST;
import org.jboss.resteasy.reactive.RestForm;
import org.jboss.resteasy.reactive.RestPath;
import io.quarkus.qute.CheckedTemplate;
import io.quarkus.qute.TemplateInstance;
import model.Todo;
public class Todos extends Controller {
    @CheckedTemplate
    static class Templates {
        public static native TemplateInstance index(List<Todo> todos);
    }
    public TemplateInstance index() {
        // list every todo
        List<Todo> todos = Todo.listAll();
        // render the index template
        return Templates.index(todos);
    }
    @POST
    public void delete(@RestPath Long id) {
        // find the Todo
        Todo todo = Todo.findById(id);
        notFoundIfNull(todo);
        // delete it
        todo.delete();
        // send loving message
        flash("message", "Task deleted");
        // redirect to index page
        index();
    }
    @POST
    public void done(@RestPath Long id) {
        // find the Todo
        Todo todo = Todo.findById(id);
        notFoundIfNull(todo);
        // switch its done state
        todo.done = !todo.done;
        if(todo.done)
            todo.doneDate = new Date();
        // send loving message
        flash("message", "Task updated");
        // redirect to index page
        index();
    }
    @POST
    public void add(@NotBlank @RestForm String task) {
        // check if there are validation issues
        if(validationFailed()) {
            // go back to the index page
            index();
        }
        // create a new Todo
        Todo todo = new Todo();
        todo.task = task;
        todo.persist();
        // send loving message
        flash("message", "Task added");
        // redirect to index page
        index();
    }
}Methods
Every public method is a valid endpoint. If it has no HTTP method annotation (@GET, @HEAD, @POST, @PUT, @DELETE) then
it is assumed to be a @GET method.
Most @GET methods will typically return a TemplateInstance for rendering an HTML server-side template, and should not
modify application state.
Controller methods annotated with @POST, @PUT and @DELETE will typically return void and trigger a redirect to a @GET
method after they do their action. This is not mandatory, you can also return a TemplateInstance if you want, but it is good form
to use a redirect to avoid involuntary actions when browsers reload the page. Those methods also get an implicit @Transactional
annotation so you don’t need to add it.
If your controller is not annotated with @Path it will default to a path using the class name. If your controller method is not
annotated with @Path it will default to a path using the method name. The exception is if you have a @Path annotation on the
method with an absolute path, in which case the class path part will be ignored. Here’s a list of example annotations and how they
result:
| Class declaration | Method declaration | URI | 
|---|---|---|
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
Furthermore, if you specify path parameters that are not present in your path annotations, they will be automatically appended to your path:
public class Orders extends Controller {
    // The URI will be Orders/get/{owner}/{id}
    public TemplateInstance get(@RestPath String owner, @RestPath Long id) {
    }
    // The URI will be /orders/{owner}/{id}
    @Path("/orders")
    public TemplateInstance otherGet(@RestPath String owner, @RestPath Long id) {
    }
}Views
You can place your Qute views in the src/main/resources/templates folder,
using the {className}/{methodName}.html naming convention.
Every controller that has views should declare them with a nested static class annotated with @CheckedTemplate:
public class Todos extends Controller {
    @CheckedTemplate
    static class Templates {
        public static native TemplateInstance index(List<Todo> todos);
    }
    public TemplateInstance index() {
        // list every todo
        List<Todo> todos = Todo.listAll();
        // render the index template
        return Templates.index(todos);
    }
}Here we’re declaring the Todos/index.html template, specifying that it takes a todos parameter of type
List<Todo> which allows us to validate the template at build-time.
Templates are written in Qute, and you can also declare imported templates in order to validate them using a
toplevel class, such as the main.html template:
package rest;
import io.quarkus.qute.CheckedTemplate;
import io.quarkus.qute.TemplateInstance;
@CheckedTemplate
public class Templates {
    public static native TemplateInstance main();
}Template composition
Typical web applications will have a main template for their layout and use composition in every method. For example, we
can declare the following main template in main.html:
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>{#insert title /}</title>
        <meta charset="UTF-8">
        <link rel="stylesheet" media="screen" href="/stylesheets/main.css">
        {#insert moreStyles /}
        <script src="/javascripts/main.js" type="text/javascript" charset="UTF-8"></script>
        {#insert moreScripts /}
    </head>
    <body>
        {#insert /}
    </body>
</html>And then use it in our Todos/index.html template to list the todo items:
{#include main.html }
{#title}Todos{/title}
<table class="table">
  <thead>
    <tr>
      <th>#</th>
      <th>Task</th>
    </tr>
  </thead>
  <tbody>
    {#for todo in todos}
    <tr>
      <th>{todo.id}</th>
      <td>{todo.task}</td>
    </tr>
    {/for}
  </tbody>
</table>
{/include}Standard tags
| Tag | Description | 
|---|---|
| Iterate over collections | |
| Conditional statement | |
| Switch statement | |
| Adds value members to the local scope | |
| Declare local variables | |
| Template composition | 
User tags
If you want to declare additional tags in order to be able to repeat them in your templates, simply place them in the
templates/tags folder. For example, here is our user.html tag:
<span class="user-link" title="{it.userName}">
{#if img??}
{#gravatar it.email size=size.or(20) default='mm' /}
{/if}
{it.userName}</span>Which allows us to use it in every template:
{#if inject:user}
    {#if inject:user.isAdmin}<span class="bi-star-fill" title="You are an administrator"></span>{/if}
    {#user inject:user img=true size=20/}
{/if}You can pass parameters to your template with name=value pairs, and the first unnamed parameter value becomes available
as the it parameter.
See the Qute documentation for more information.
Renarde tags
Renarde comes with a few extra tags to make your life easier:
| Tag | Description | 
|---|---|
| 
 | Generate a hidden HTML form element containing a CSRF token to be matched in the next request. | 
| 
 | Inserts the error message for the given field name | 
| 
 | Generates an HTML form for the given  | 
| 
 | Inserts a gravatar image for the given  | 
| 
 | Conditional statement executed if there is an error for the given field | 
Extension methods
If you need additional methods to be registered to be used on your template expressions, you can declare static methods in
a class annotated with @TemplateExtension:
package util;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import io.quarkus.qute.TemplateExtension;
@TemplateExtension
public class JavaExtensions {
    public static boolean isRecent(Date date){
        Date now = new Date();
        Calendar cal = new GregorianCalendar();
        cal.add(Calendar.MONTH, -6);
        Date sixMonthsAgo = cal.getTime();
        return date.before(now) && date.after(sixMonthsAgo);
    }
}This one declares an additional method on the Date type, allowing you to test whether a date is recent or not:
{#if todo.done && todo.doneDate.isRecent()}
    This was done recently!
{/if}Renarde extension methods
| Target type | Method | Description | 
|---|---|---|
| 
 | 
 | Formats the date to the  | 
| 
 | 
 | Formats the date to the  | 
| 
 | 
 | Returns  | 
| 
 | 
 | Formats the date in terms of  | 
| 
 | 
 | Returns an MD5 hash of the given string | 
| 
 | 
 | Returns true if the given object is exactly of the specified class name | 
Global Variables
If you need to pass variables to every template, instead of passing them manually to every view, you can define them as
methods in a class annotated with @TemplateGlobal:
package util;
import io.quarkus.qute.TemplateGlobal;
@TemplateGlobal
public class Globals {
    public static String lineSeparator(){
        return System.lineSeparator();
    }
}This one declares a lineSeparator global variable that you can use in the views:
This system uses this line separator: {lineSeparator}Renarde Predefined Global Variables
| Type | Name | Description | 
|---|---|---|
| 
 | 
 | The absolute request url, including scheme, host, port, path | 
| 
 | 
 | The request method ( | 
| 
 | 
 | The request HTTP scheme ( | 
| 
 | 
 | The request authority part (ex:  | 
| 
 | 
 | The request host name (ex:  | 
| 
 | 
 | The request port (ex:  | 
| 
 | 
 | The request path (ex:  | 
| 
 | 
 | The controller endpoint class and method (ex:  | 
| 
 | 
 | True if the request is served over SSL/HTTPS | 
| 
 | 
 | The remote client IP address | 
| 
 | 
 | The remote client Host name, if available | 
| 
 | 
 | The remote client port | 
External CSS, JavaScript libraries
You can use jars created by mvnpm.org to provide third-party JavaScript or CSS hosted on the NPM Registry.
For example, here is how you can import Bootstrap and Bootstrap-icons in your pom.xml:
<dependency>
  <groupId>org.mvnpm</groupId>
  <artifactId>bootstrap</artifactId>
  <version>5.3.3</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>org.mvnpm</groupId>
  <artifactId>bootstrap-icons</artifactId>
  <version>1.11.3</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-web-dependency-locator</artifactId>
</dependency>After that, you can include them in your Qute templates with:
<head>
    <link rel="stylesheet" media="screen" href="/_static/bootstrap/dist/css/bootstrap.css">
    <link rel="stylesheet" media="screen" href="/_static/bootstrap-icons/font/bootstrap-icons.css">
    <script src="/_static/bootstrap/js/bootstrap.min.js" type="text/javascript" charset="UTF-8"></script>
</head>Check the web-dependency-locator extension guide for more information.