vai al contenuto principale

Sviluppo di risorse REST via plugin

I CloudletRestletPlugin sono dei particolari plugin basati sul framework Restlet, che permettono di aggiungere risorse REST o GraphQL personalizzate a quelle generabili automaticamente dalle Cloudlet.

In questa guida illustriamo i CloudletRestletPlugin come metodo per aggiungere risorse REST o GraphQL personalizzate all’interno di una Cloudlet e diamo dei cenni sulla loro implementazione.

Panoramica #

Una Cloudlet è in grado di generare risorse GraphQL che consentono operazioni CRUD sui suoi elementi e l’invocazione diretta dei FormActionHandler. A queste si aggiungono i CloudletRestletPlugin, che si basano sul framework Restlet e consentono di soddisfare ulteriori casi d’uso, come la costruzione di uno snippet HTML da far renderizzare a un browser o la generazione di valori casuali.

Al pari degli ScheduledTask, i CloudletRestletPlugin non sono oggetti del modello e vanno implementati direttamente nella base di codice.

Un plugin di questo tipo estende la classe astratta RestletServerResource ed è decorato con l’annotazione @CloudletRestletServerResource:

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

Note implementative #

Per implementare un CloudletRestletPlugin vanno seguite le linee guida relative alla configurazione di un progetto Java e alla sua successiva programmazione nella sezione Ciclo di sviluppo.

Lo sviluppatore deve costruire una nuova classe che estende dal tipo astratto RestletServerResource, implementando i due metodi astratti getType() e getUrl():

  • getType() deve restituire un valore enumerato tra PUBLIC_EXT, PUBLIC_GRAPHQL, AUTH_EXT e AUTH_GRAPHQL. Il valore di ritorno definisce il tipo di risorsa rappresentato dalla classe, la quale può essere pubblica (PUBLIC) o necessitante di autenticazione (AUTH), e di natura REST o GraphQL;
  • getUrl() deve restituire una stringa costituita da un nome semplice (es. myResource) o un path relativo completo (es. path/to/myResource). Definisce l’URL presso cui la risorsa sarĂ  disponibile.

L’indirizzo dell’endpoint del plugin è nella forma <CloudletUrl>/<AccessLevel>/api/<ResourceType>/<ResourceUrl> e viene costruito come segue:

  • <CloudletUrl> è l’URL della Cloudlet per cui stiamo realizzando il CloudletRestletPlugin;
  • <AccessLevel> viene valorizzato a public se la risorsa è esposta pubblicamente, o a auth se la risorsa richiede autenticazione;
  • <ResourceType> se la risorsa è di tipo REST o GraphQL, viene rispettivamente valorizzato a ext o graphql;
  • <ResourceUrl> viene valorizzato all’URL restituito da getUrl().

A questo punto va definita la risposta fornita dall’endpoint personalizzato, implementando un ulteriore metodo da annotare con la tipologia di comando HTTP, come @Get o @Post: l’annotazione può accettare un parametro di tipo stringa che specifica la formattazione da applicare al risultato; per esempio, indicando @Get("json") la risposta dovrà essere restituita nel formato JSON.

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

All’interno di questo metodo è possibile richiamare i servizi della Cloudlet, che in questo caso non vanno iniettati da costruttore ma sono già forniti nel contesto della risposta. Lo sviluppatore può accedervi direttamente invocando uno dei metodi della classe astratta RestletServerResource: per esempio il database della Cloudlet, come DataSource, si ottiene invocando getDataSource().

Esempio #

Il seguente esempio riunisce tutti i concetti finora mostrati:

@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 + "]";
  }
}

Stiamo definendo una risorsa REST di tipo autenticato (getType() restituisce il valore AUTH_EXT), reperibile all’indirizzo <CloudletUrl>/auth/api/ext/myExt, che risponde con i nomi e i cognomi degli impiegati memorizzati nella nostra Cloudlet.

La risposta è fornita dal metodo myService(), che è annotato con @Get("json"): questo significa che dobbiamo inoltrare una richiesta con il comando HTTP Get, ottenendo una stringa formattata come JSON. All’interno notiamo l’utilizzo del metodo getDataSource() della classe astratta, che ci fornisce l’accesso al DataSource della Cloudlet, al quale chiediamo l’apertura di una connessione con getConnection(): la utilizziamo per sottomettere uno statement JDBC che ci restituisce l’intero insieme degli impiegati nella tabella employee che corrisponde all’omonima classe, proiettandolo sui soli campi firstName e lastName.

Fatto ciò, scansioniamo il risultato dello statement trasformando ciascun record in una stringa JSON opportunamente formattata, per poi riunirli tutti in una ulteriore stringa che restituiremo, rappresentante una lista in JSON.

Riferimenti #

Nella presente guida abbiamo mostrato le caratteristiche basilari del framework Restlet, le quali permettono di coprire i casi d’uso più semplici.

Per ulteriori dettagli, rimandiamo alla documentazione di Restlet.