Type-safe Templates
Type-safe Templates
There’s an alternate way to declare your templates in your Java itself, which relies on the following convention:
 
- Organize your template files in the /src/main/resources/templatesdirectory by grouping them into one directory per resource class. For example, if yourItemResourceclass references two templateshelloandgoodbye, place them at/src/main/resources/templates/ItemResource/hello.txtand/src/main/resources/templates/ItemResource/goodbye.txtrespectively. Grouping templates per resource class makes it easier to navigate to them.
- In each of your resource classes, declare a @CheckedTemplate static class Template {}class within your resource class.
- Declare one public static native TemplateInstancemethod per template file for your resource.
- Use those static methods to build your template instances.
Creating a Simple Template
Create a directory to hold templates for our HelloResource class (run this command from the root directory of the project):
mkdir -p src/main/resources/templates/HelloResource
Create a new file at src/main/resources/templates/HelloResource/hello.txt and set the contents to be:
Hello {name} from HelloResource!
Warning: Note that thehello.txtfile in the previous step is located directly in thetemplatesdirectory. Since this example is using the alternate convention, you'll be creating another file with the same name in theHelloResourcesubdirectory.
For the goodbye template, create a new file at src/main/resources/templates/HelloResource/goodbye.txt and enter the contents:
Goodbye {name} from HelloResource!
Even though you created new template files for this new convention, the code will still exist in the HelloResource.java file. Open that file (src/main/java/org/acme/HelloResource.java) and replace the existing contents with the following:
 
package org.acme;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.CheckedTemplate;
@Path("hello")
public class HelloResource {
    @CheckedTemplate(requireTypeSafeExpressions = false)
    public static class Templates {
        public static native TemplateInstance hello(String name);
        public static native TemplateInstance goodbye(String name);
    }
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public TemplateInstance get(@QueryParam("name") String name) {
        return HelloResource.Templates.hello(name);
    }
}
A few notes on the updated code:
- This code expects to use a template at the path templates/HelloResource/hello.txt, since the@CheckedTemplatestatic class is declared inside theHelloResourceclass. The name of the method,hello, is used to match files in the directory with common extensions like.txtor.html. You can specify an exact name and path using@ResourcePath.
- The Templates.hello()method returns a new template instance that can be customized before the actual rendering is triggered. In this case, you put the name value under the keyname. The data map is accessible during rendering.
- Again, notice that we don’t explicitly trigger the rendering - this is done automatically.
- Once you have declared a @CheckedTemplateclass, Quarkus will check that all of its methods point to existing templates. As a result, if you try to use a template from your Java code and you forgot to add it, Quarkus will let you know at build time.
Keep in mind this style of declaration allows you to reference templates declared in other resources too.
Creating the Goodbye Resource
To fulfill the goodbye endpoint, you need to create a new resource.
 
src/main/java/org/acme/GoodbyeResource.java and enter the following contents:
package org.acme;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import io.quarkus.qute.TemplateInstance;
@Path("goodbye")
public class GoodbyeResource {
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public TemplateInstance get(@QueryParam("name") String name) {
        return HelloResource.Templates.goodbye(name);
    }
}
Testing the Endpoints
Let's start by testing the new implementation of the hello endpoint:
curl http://localhost:8080/hello?name=Daniel
You should see:
Hello Daniel from HelloResource!
curl http://localhost:8080/goodbye?name=Daniel
This time, you should see the goodbye template in use:
Goodbye Daniel from HelloResource!
As stated earlier, since the TemplateInstance is declared as an inner class inside of HelloResource, Qute will attempt to locate the template in the HelloResource/ subdirectory. If instead, you want to create a top-level declaration, you can do this inside a separate class (do not copy this code for this exercise):
@CheckedTemplate
public class Templates {
    public static native TemplateInstance hello();
    public static native TemplateInstance goodbye();
}
This will cause Qute to look for the associated hello.txt or goodbye.txt in the src/main/resources/templates directory, instead of src/main/resources/templates/HelloResource. It is up to you how you wish to organize your templates.
