skip to main content

Development of REST resources via plugins

CloudletRestletPlugins are special plugins based on the Restlet framework, which allow custom REST or GraphQL resources to be added to those automatically generated by Cloudlets.

In this guide we illustrate the CloudletRestletPlugin as a method to add custom REST or GraphQL resources inside a Cloudlet and give an overview of their implementation.

Overview #

A Cloudlet is able to generate GraphQL resources that allow CRUD operations on its elements and the direct invocation of FormActionHandlers. In addition to these are CloudletRestletPlugin, which are based on the Restlet framework and allow to satisfy further use cases, such as building an HTML snippet for a browser to render or generating random values.

Similar to the ScheduledTask, the CloudletRestletPlugin are not model objects and have to be implemented directly in the code base.

Such a plugin extends the abstract RestletServerResource class and is decorated with the @CloudletRestletServerResource annotation:

@CloudletRestletServerResource
public class MyRestletResource extends RestletServerResource {
  //...
}

Implementation notes #

To implement a CloudletRestletPlugin follow the guidelines for setting up a Java project and its subsequent programming in the Development Cycle section.

The developer must build a new class that extends from the abstract type RestletServerResource, implementing the two abstract methods getType() and getUrl():

  • getType() must return an enumerated value between PUBLIC_EXT, PUBLIC_GRAPHQL, AUTH_EXT, and AUTH_GRAPHQL. The return value defines the type of resource represented by the class, which may be public (PUBLIC) or requiring authentication (AUTH), and may be REST or GraphQL;
  • getUrl() must return a string consisting of a simple name (e.g. myResource) or a full relative path (e.g. path/to/myResource). Defines the URL where the resource will be available.

The address of the plugin endpoint in the form <CloudletUrl>/<AccessLevel>/api/<ResourceType>/<ResourceUrl> and is constructed as follows:

  • <CloudletUrl> the URL of the Cloudlet for whom we are creating the CloudletRestletPlugin;
  • <AccessLevel> is set to public if the resource is publicly exposed, or to auth if the resource requires authentication;
  • <ResourceType> if the resource is of REST or GraphQL type, it is respectively set to ext or graphql;
  • <ResourceUrl> is set to the URL returned by getUrl().

Now define the response provided by the custom endpoint, implementing a further method to be annotated with the HTTP command type, such as @Get or @Post: the annotation can accept a string parameter specifying the formatting to apply to the result; for example, indicating @Get("json") the response should be returned in JSON format.

@Get("json")
public String getPerson() {
  return "{ \"firstName\" : \"Mario\", \"lastName\" : \"Rossi\"}"
}

Inside this method you can access the Cloudlet services, which in this case don’t need to be injected by the constructor but are already provided in the context of the response. The developer can access them directly by invoking one of the methods of the abstract class RestletServerResource: for example the Cloudlet database, as DataSource, is obtained by invoking getDataSource().

Example #

The following example brings together all the concepts shown so far:

@CloudletRestletServerResource
public class MyExtRestletResource extends RestletServerResource {

  @Override
  public RestletServerResourceType getType() {
    return AUTH_EXT;
  }

  @Override
  public String getUrl() {
    return "myExt";
  }

  @Get("json")
  public String myService() {
    List<String> employeeJsons = new LinkedList<>();
    try (Connection c = getDataSource().getConnection()) {
      ResultSet rs = c.prepareStatement("SELECT firstName, lastName FROM `employee`").executeQuery();
      while (rs.next()) {
        String firstName = rs.getString("firstName");
        String lastName = rs.getString("lastName");
        employeeJsons.add(String.format("{ \"firstName\" : \"%s\", \"lastName\" : \"%s\" }"));
      }
    }
    catch (Exception e) {
      throw new RuntimeException(e);
    }

    String jsonRes = String.join(employeeJsons, ",");
    return "[" + jsonRes + "]";
  }
}

We’re defining a REST resource of authenticated type (getType() returns the value AUTH_EXT), found at <CloudletUrl>/auth/api/ext/myExt, which responds with the first and last names of employees stored in our Cloudlet.

The response is provided by the myService() method, which is annotated with @Get("json"): this means that we have to forward a request with the HTTP Get command, getting a string formatted as JSON. Inside, we notice the use of the getDataSource() method of the abstract class, which gives us access to the Cloudlet’s DataSource, to which we ask for a connection to be opened with getConnection(): we use it to submit a JDBC statement that returns the whole set of employees in the employee table that corresponds to the class of the same name, projecting it onto just the firstName and lastName fields.

Now we can scan the result of the statement, transforming each record into a suitably formatted JSON string, and then combine them all into a further string that we return, representing a list in JSON.

References #

In this guide we have shown the basic features of the Restlet framework, covering the simplest use cases.

For more details, see Restlet documentation.