Restlet 1.0 - Developer FAQ

Note that there is another FAQ covering more general questions about the framework and REST.

Table of contents

  1. How can I get the raw HTTP headers if I really need to?
  2. Can I run Restlets inside Tomcat or any Servlet container?
  3. Can the Restlets composing a site be defined in an XML file?
  4. What JAR files must I have in my classpath for a minimal application?
  5. What are the other JAR files for?
  6. How do I provide password protection on a server?
  7. How do I check the mime type of a document PUT on my server?
  8. How do I attach a status report to a client GET when the call fails on my server?
  9. What about performance, are new Restlets created for each call received on my server?
  10. How do I implement the traditional MVC pattern?
  11. Any recommendations/guidelines in terms of how to deal with caching?
  12. What is the performance of the HTTP connectors?
  13. Why is my HTTP client sending unwanted "application/x-www-form-urlencoded" content type headers?
  14. Can a Filter modify the call like a Servlet Filter?
  15. My server is running behind a proxy, can I get the actual client IP address?
  16. Is there a mechanism to pass data sets to downstream Restlets?
  17. What is the difference between a Filter and a Router?
  18. How can I send and receive files with Restlet?
  19. How can I make PUT or DELETE calls from browsers?
  20. What's the best practice for error handling in an intermediate Restlet?
  21. What is the best way to use Restlet in Eclipse?
  22. How can I change the parameters of my connector?
  23. How can I integrate with Spring?
  24. Can I prevent child URIs from being matched by Routers?

1. How can I get the raw HTTP headers if I really need to?

All standard HTTP headers have an equivalent class/property in the Restlet API. It was a deliberate choice to not expose those headers as first-class citizens, because we consider them as lower-level artifacts and because we want to support multiple protocols via the same API.

However, it is sometimes necessary to access to the raw HTTP headers or to add non-standard headers. For this purpose, we use special Request and Response attributes, see details in Javadocs of the Message.getAttributes() method. There is also a sample code in the distribution that illustrates how to get raw headers and how to add non-standard ones, see the org.restlet.example.misc.HeadersTest class in the "src" directory.

2. Can I run Restlets inside Tomcat or any Servlet container?

Yes you can, even if this is not required. If you can't use the standalone HTTP connectors provided in the Noelios Restlet Engine, you can still use the ServerServlet connector which is an adapter between the Servlet API and the Restlet API. See the ServerServlet Javadocs for details on how to configure your Servlet container.

Here is the description of a concrete simple Web application. All sources are available here.
Imagine your simple application is only composed of one package and one class :
  • Package "com.testServlet"
  • Class "com.testServlet.TestServletApplication"
Your application's root restlet is very simple and is in charge of displaying some data taken from the client in an HTML format. Your application contains also a "main" method in order to provide the standalone mode.
In standalone mode, the following jars are required in the classpath :
  • The standard Restlet API : "org.restlet.jar"
  • The core Noelios Restlet Engine : "com.noelios.restlet.jar"
  • One server connector that supports the HTTP Protocols. For example, use the Simple HTTP Connector : "com.noelios.restlet.ext.simple_3.1.jar" and "org.simpleframework.jar".

If you want to deploy your application in a servlet container such as Tomcat, the following jar files are required in your deployment package :
  • The standard Restlet API : "org.restlet.jar"
  • The core Noelios Restlet Engine : "com.noelios.restlet.jar"
  • The servlet connector : "com.noelios.restlet.ext.servlet_2.4.jar"
Then organize your application as follows before generating the Web Application aRchive (e.g. in a WAR file ) :
  • /WEB-INF/classes/ - your package and the compiled classes.
  • /WEB-INF/lib/ - the required jar files.
  • /WEB-INF/web.xml - The Web Application Deployment Descriptor for your application.
Here is a sample configuration of such web.xml file for our simple Restlet webapp :
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC
   "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
   "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
    <display-name>Test servlet</display-name>
    <context-param>
            <param-name>org.restlet.application</param-name>
            <param-value>
               com.testServlet.TestServletApplication
            </param-value>
    </context-param>

    <!-- Restlet adapter -->
    <servlet>
            <servlet-name>ServerServlet</servlet-name>
            <servlet-class>
               com.noelios.restlet.ext.servlet.ServerServlet
            </servlet-class>
    </servlet>

    <!-- Catch all requests -->
    <servlet-mapping>
            <servlet-name>ServerServlet</servlet-name>
            <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>
      

3. Can the Restlets composing a site be defined in an XML file?

As XML has been frequently overused as an alternative programming language, in the Restlet framework we are very careful about this. We think that any configuration that must be done by an application developer should be done in Java. In the future, we plan to support XML configuration for the Component as this task will often by delegated to an administrator without Java knowledge. As you can see in our Community Wiki, several users have integrated Restlet with other frameworks like Spring, which support XML configuration itself.

4. What JAR files must I have in my classpath for a minimal application?

In a Restlet distribution, all JAR files are located under the "lib" directory. The org.restlet.jar file is containing the standard Restlet API. Even though you can compile your code with only this JAR file, it is likely that you'll need the additional features provided by the various Restlet extensions in the org.restlet.ext.*.jar files. In any case, to run a minimal application, you'll also need an implementation of the API, the core Noelios Restlet Engine contained in com.noelios.restlet.jar.

5. What are the other JAR files for?

The core NRE doesn't contain any connector to receive or send requests. You need to add to your classpath the JAR file of each additional connector needed by your application. Check the "/lib/README.txt" file in the distribution for a detailled list of all the required dependencies for each extension JAR. If you want to act as an HTTP server, you can choose between several connectors: standalone ones based on Jetty, Simple Framework and AsyncWeb, and one embedded if you want to use an existing Servlet container like Tomcat.

There are other extensions to the NRE, like HTTP, SMTP and JDBC clients. Each one corresponds to a seperate Java package under com.noelios.restlet.ext.* and is packaged as a separate JAR file available under the "lib" directory. For example, if you need to send emails, you must include the following JAR files: /lib/com.noelios.restlet.ext.javamail_1.4.jar (NRE extension) and /lib/javax.mail_1.4/mail.jar (JavaMail).

No further configuration is needed as the NRE runtime will automatically detect the extensions present if the application classpath. This is the reason why you can rely on the standard Restlet API to create connectors, for example: new Server(Protocol.HTTP, 8182, target).

6. How do I provide password protection on a server?

Currently, the Noelios Restlet Engine supports Basic HTTP and Amazon Web Services authentication schemes. You order to leverage them, use the Guard Filter. For details on how to use this Filter, please check the part 9 of the tutorial.

7. How do I check the mime type of a document PUT on my server?

This is simple: request.getEntity().getMediaType() which returns an instance of the MediaType class. From this instance you can get the main and sub types as well as the optional type parameters.

8. How do I attach a status report to a client GET when the call fails on my server?

This is also simple: response.setStatus(Status.CLIENT_ERROR_NOT_FOUND). Of course you have a complete list of options available in the Status class, closely following the HTTP and WebDAV conventions.

Finally, a description can be added to the status report to help the client understand the situation and correct its request if needed. For this purpose, you can create new instances of the Status class instead of using the constants or, more simply, you can use response.setStatus(Status.CLIENT_ERROR_NOT_FOUND, "Your comment goes here").

9. What about performance, are new Restlets created for each call received on my server?

For a server connector such as Jetty HTTP, the main cost of Restlets resides in the creation of the Request and Response objects from the low-level HTTP request headers and body. This cost is low and is optimized to parse the required headers only when the application actually needs the information.

For the rest, the Restlet cost happens upon initialization or first call. By default, Restlet objects (including Filters, Finders and Routers) are shared by all calls. As calls are living in separate threads, they can be concurrently processed by the Restlets. You only need to be careful when using member variables to store temporary state. If at some point in your application, you need to have state that is specific to your call, you should use the Request.getAttributes() or Response.getAttributes() as a modifiable map of attributes. In the final Finder, a new instance of the target Resource class is automatically by default, which let you deal call's specific information.

For those concerned by performance, we have published a benchmark illustrating that Restlets are scalable and efficient.

10. How do I implement the traditional MVC pattern?

Here is the basic proposition for implementing the MVC pattern with Restlets:

  1. Controller == Restlets (mainly Filters, Routers, Finders). You can visualize the controller as a sort of processing chain, where the last node should be a Hander with all the information necessary to locate the target Resource for the call. This location information can be stored either in the request's attributes map, either in the member variables of a request wrapper (see org.restlet.WrapperRequest). This last Finder should override the findTarget(Request, Response) method and return an instance of Resource.
  2. Model == Resource + data objects. Just start from the org.restlet.resource.Resource class and implement its methods like getVariants(), post(), delete() and put(). The Finder class automatically invokes those methods by implementing the handleGet(), handleHead(), handlePost(), handlePut(), handleDelete() methods for you. For example, you just need to override the getVariants() to benefit from automatic content negotiation. Internally, we rely on the Response.setEntity(Resource, Language) method to trigger this content negotiation, which compares the representations that you make available (named the variants), with the client capabilities and preferences.
  3. View == Representation. To create new representations for your resources, you can rely on one of the numerous Representation implementation classes (InputRepresentation for example) available in the org.restlet.resource package or in extension packages like for JSON documents, FreeMarker and Velocity templates.

11. Any recommendations/guidelines in terms of how to deal with caching?

Currently, client-side caching is supported via the "conditions" property of Call. See the Conditions class for details. So, the first recommendation is to ensure that you correctly set all the representation metadata for your own representations (modification date, expiration date, tag). That will ensure that the server-side negotiation logic (used via the Response.setEntity(Resource, Language) method) works optimally.

Then, writing a generic server-side cache is a different story. The recommendation would be to follow the REST style and HTTP specification spirit as closely as possible. For full-featured caching, you should look at popular projects like Squid: http://www.squid-cache.org/ or Apache caching modules. These caches can be installed transparently for the clients, as reverse proxies.

12. What is the performance of the HTTP connectors?

For server connectors, the performance will depend on the actual provider used and whether you deploy your application with a standalone connector or embedded in a Servlet container. We have published a benchmark illustrating that Restlets are scalable and efficient, but encourage you to do your own tests within your target deployment environment.

13. Why is my HTTP client sending unwanted "application/x-www-form-urlencoded" content type headers?

When you do a simple GET with the Restlet HTTP client connector based on JDK's HttpURLConnection, an extra "content-type" header can be sent to the server, even though your call doesn't provide any input content (because you just GET a representation). This is due to a bug in JDK 5.0 that was fixed in update 10 and in JDK 6.0 as indicated in the bug report.

14. Can a Filter modify the call like a Servlet Filter?

Absolutely! What the tutorial only says is that request's base reference should rarely be modified. Beside that, anything else in the request or response objects can be modified, before or after the handling of the call by the attached Restlet.

15. My server is running behind a proxy, can I get the actual client IP address?

The immediate client IP address available is the only that is always available because its based on the underlying protocol connection. In HTTP, certain proxies do transfer the original client IP address (or addresses) by using some extra HTTP headers like "X-Forwarded-for". In the recent Restlet versions you can get all this information in a straightforward way. On the ClientInfo class, accessible via the getClientInfo() method, you have two related methods getAddress() and getAddresses(). Please check the Javadocs of the HTTP server connectors for details (i.e. context parameter to set) on how to enable the support for the "X-Forwarded-For" header as there are some security risks when using it, especially if you are not controlling the intermediary proxies.

16. Is there a mechanism to pass data sets to downstream Restlets?

Yes, there are multiple mechanisms available. If you need to store state, without any validation logic or behavior, you can use the Request.getAttributes() method which returns a modifiable map object. Otherwise, you can wrap the Request object into a larger one containing the extra properties and methods that you need. For this purpose, you just have to create a subclass of org.restlet.util.WrapperRequest. Then, in one of your handle methods, you can simply wrap the current call instance. Unless you use a common base Restlet you will need to properly cast the call instance in subsequent Restlets in order to access to your wrapper methods.

17. What is the difference between a Filter and a Router?

Filters support some processing before or after the handling of a call by a target Restlet. They are useful for actions like logging, caching, compressing or security checks. The purpose of Routers is to route calls based on some any useful criteria, typically base on the relative target URI. Routers can distribute calls to one or more attached Restlets using intermediary Routes. A Route is a simple Filter where the target Restlet is attached and that can score incoming calls. Depending on the Routes and the routing algorithm used, the Router will select the most appropriate target Restlet to continue the processing of the call. Default Routes based on URI patterns will also update the "Request.resourceRef.baseRef" property before actually invoking the selected target Restlet. See also, this FAQ entry for a comparison of Routers with the Servlet API.

18. How can I send and receive files with Restlet?

To receive large files, from browsers for example, you can rely on the Apache FileUpload project which was integrated as a Restlet Extension. To send a file using the HTTP client connector, just create a new FileRepresentation and set is as the input of your call.

19. How can I make PUT or DELETE calls from browsers?

There are two solutions to this problem. The first one is to tunnel the PUT or DELETE calls through regular POST calls. There is a TunnelService associated with each Application that automatically takes care of it. Also, in the Using REST with Ajax article, the author explains how to directly build the PUT and DELETE methods from a browser using some JavaScript code.

20. What's the best practice for error handling in an intermediate Restlet?

Typically, unexpected exceptions are handled at the Application level, by setting the status to 500 (internal server error). If you want a different status when an exception is thrown, you have to catch it manually at a lower level (inside the handle(Call) or handleGet|Post|etc. method of your intermediary Restlet) and set the desired status on your response.

21. What is the best way to use Restlet in Eclipse?

Of course, you could manually use the JAR files in your Eclipse projects, but the most flexible way is to rely on Eclipse's plug-in infrastructure. Here are some detailed steps to get you started:

  1. Drop the content of the Restlet's "lib/" directory into Eclipse's plug-in directory
  2. Restart Eclipse and go into "Help/About Eclipse SDK" menu
  3. In the new dialog, click on the "Plug-in Details" button
  4. In the new dialog, you should see the registered plugins, for example under the "Noelios Consulting" provider name

Now in order to use those plugins:

  1. Select "New Project" and choose "Plug-in Project"
  2. Click "Next >", eeter a project name and click "Next >" again
  3. Disable the plug-in options checkboxes (unless you do need them)
  4. Click "Finish" and you should see you new project with the plug-in "Overview" panel displayed
  5. Select the "Dependencies" tab and click "Add..." in the "Required Plug-ins..." section
  6. Select the plugins you need, start by either "org.restlet", "com.noelios.restlet" or the package name for third-party libraries (Jetty, Servlet API, etc.).

Now you're done! You can create new classes and import the org.restlet.* packages to work with Restlets. Note, that if you add several server HTTP dependencies, only the first one in the list will be use to create connectors.

Also note that you can't add a dependency to Jetty 5 and Jetty 6 at the same time as it will result in a security exception as you experienced, because they use overlapping package names.

22. How can I change the configuration of my connector?

Each connector has a set of specific parameters that can be changed to tune their default configuration. Changing those parameters doesn't require a direct access to the connector internal classes. Here is an example illustrating how to change the request buffer size for the Jetty connector:

Server myServer = new Server(Protocol.HTTP, 8182, restlet);
myServer.getContext().getParameters().add("requestBufferSize", "30000");
myServer.start();
   

23. How can I integrate with Spring?

During the development of the 1.0 version of the API, several users attempted to integrate Restlet with Spring. They were especially trying to use the XML-based bean wiring feature of Spring. This resulted in several examples available on the community Wiki.

In order to facilitate this integration, a dedicated Spring extension was added to the Restlet distribution and the Servlet extension was modified. It allows us to provide two main integration modes.

In the first mode, the goal is to leverage the concept of Restlet Application and all the associated services, as well as the transparent deployment to either a Servlet container (using the adapter ServerServlet extension class) or using a standalone HTTP server connector. For this, you can leverage the SpringContext class which is a Spring's GenericApplicationContext subclass. You can associate a list of property-based on XML-based configuration URIs (file:/// or war:/// URIs) in order to have Spring auto-instantiate and wire your Restlet beans.

In the second mode, the goal is to leverage the concept of Spring Web Application as an alternative to the Restlet Application. This is sometimes required when the Restlet code is only part of a much larger Spring-based Web application, with dependencies on the Servlet API. Initially, it was hard to achieve this integration because the Servlet extension, and especially the ServerServlet adapter class was assuming the usage of a Restlet Application. This was redundant in this mode so we later added a lighter adapter based on the ServletConverter class. With this converter, you can directly instantiate Restlet Routers, Finders and Resources from your existing Servlet-based Spring code. Check the Javadocs for details.

Finally, there is also a SpringFinder class available in the Spring extension. It hasn't any specific dependency to Spring, but the addition of a parameter-less createResource() method allows the usage of the Spring's "lookup-method" mechanism.

24. Can I prevent child URIs from being matched by Routers?

The default behavior of a Router is to match the beginning of the request URI (actually the remaining part, left by previous Routers) with the attached URI patterns. If the request URI indeed starts with one of the URI patterns, the target Resource or Restlet is invoked.

This default behavior is desirable to allow optional query strings in URI routing. However, it is sometimes preferred to be stricter about the match and to require that the request URI exactly matches the URI pattern, with no remaining part. In order to obtain this behavior, you just need to change the matching mode for the attached template. Here is a sample code:

Route route = router.attach("/users/{user}", UserResource.class);
route.getTemplate().setMatchingMode(Template.MODE_EQUALS);
   

Note that after doing this, your Router won't accept URI with query strings going to this Resource. To solve this, you can explicitely allow the query part in your URI template:

Route route = router.attach("/users/{user}?{query}", UserResource.class);
route.getTemplate().setMatchingMode(Template.MODE_EQUALS);
   

Notes

  • Thanks to Dave Pawson for drafting the first version of this FAQ.