API multiclasse

Se una singola API è particolarmente complessa, ti consigliamo di implementarla più classi Java. Per includere classi diverse nella stessa API, devi:

Ad esempio, le due classi seguenti fanno entrambe API tictactoe:

@Api(name = "tictactoe", version = "v1")
class TicTacToeA {  }

@Api(name = "tictactoe", version = "v1")
class TicTacToeB {  }

La configurazione dell'API viene specificata tramite le proprietà di annotazione @Api. Tuttavia, per più classi nella stessa API, i requisiti di @Api vanno oltre la semplice presenza delle stesse stringhe name e version nell'annotazione @Api per ogni classe. Infatti, l'API di backend non funzionerà se esistono eventuali differenze nelle configurazioni dell'API specificate nelle proprietà @Api delle classi. Qualsiasi differenza nelle proprietà @Api per i corsi in un l'API multiclasse restituisce un risultato "ambiguo" alla configurazione API, che non funzionare nei framework di Cloud Endpoints per App Engine.

Esistono diversi modi per creare un'API multiclasse non ambigua:

  • Assicurati manualmente che tutte le classi in una singola API abbiano lo stesso identico @Api di annotazioni.
  • Utilizza l'ereditarietà delle annotazioni tramite l'ereditarietà Java. In questa ereditarietà, tutte le classi in una singola API ereditano la stessa API da una classe base con annotazioni @Api comune.
  • Utilizza l'ereditarietà delle annotazioni tramite @ApiReference su tutte le classi in una singola API per fare in modo che facciano riferimento allo stesso configurazione API da una classe comune annotata con @Api.

Utilizzo di @ApiClass per le proprietà che possono variare tra le classi

Per utilizzare questa funzionalità, è necessaria la seguente importazione:

import com.google.api.server.spi.config.ApiClass;

Sebbene tutte le proprietà nell'annotazione @Api debbano corrispondere per tutte le classi di un'API, puoi utilizzare anche l'annotazione @ApiClass per fornire proprietà che non devono essere esattamente uguali tra le classi. Ad esempio:

// API methods implemented in this class allow only "clientIdA".
@Api(name = "tictactoe", version = "v1")
@ApiClass(clientIds = { "clientIdA" })
class TicTacToeA {  }

// API methods implemented in this class provide unauthenticated access.
@Api(name = "tictactoe", version = "v1")
class TicTacToeB {  }

dove TicTacToeA limita l'accesso utilizzando una lista consentita di ID client contenente l'ID client consentito e TicTacToeB non limita l'accesso.

Tutte le proprietà fornite dall'annotazione @ApiClass hanno una proprietà equivalente nell'annotazione @Api. Tieni presente che la proprietà equivalente @Api funge da valore predefinito per l'intera API. Se esiste un'impostazione predefinita a livello di API, stessa proprietà, specificata in @Api, la proprietà @ApiClass specifica per la classe sostituisce l'impostazione predefinita a livello di API.

I seguenti esempi illustrano la sostituzione delle proprietà @Api da parte del equivalenti @ApiClass specifici per la classe:

// For this class "boards" overrides "games".
@Api(name = "tictactoe", version = "v1", resource = "games")
@ApiClass(resource = "boards")
class TicTacToeBoards {  }

// For this class "scores" overrides "games".
@Api(name = "tictactoe", version = "v1", resource = "games")
@ApiClass(resource = "scores")
class TicTacToeScores {  }

// For this class, the API-wide default "games" is used as the resource.
@Api(name = "tictactoe", version = "v1", resource = "games")
class TicTacToeGames {  }

Eredità delle annotazioni

Le proprietà di annotazione @Api e @ApiClass possono essere ereditate da altre classi e le singole proprietà possono essere sostituite tramite l'eredità Java o l'eredità @ApiReference.

Utilizzo dell'ereditarietà Java

Una classe che estende un'altra classe con annotazioni @Api o @ApiClass si comporta come se fosse annotata con le stesse proprietà. Ad esempio:

@Api(name = "tictactoe", version = "v1")
class TicTacToeBase {  }

// TicTacToeA and TicTacToeB both behave as if they have the same @Api annotation as
// TicTacToeBase
class TicTacToeA extends TicTacToeBase {  }
class TicTacToeB extends TicTacToeBase {  }

Le annotazioni vengono ereditate solo tramite la sottoclasse Java, non tramite l'implementazione dell'interfaccia. Ad esempio:

@Api(name = "tictactoe", version = "v1")
interface TicTacToeBase {  }
// Does *not* behave as if annotated.
class TicTacToeA implements TicTacToeBase {  }

Di conseguenza, non è supportato alcun tipo di ereditarietà multipla delle annotazioni dei framework.

L'ereditarietà funziona anche per @ApiClass:

@ApiClass(resource = "boards")
class BoardsBase {  }

// TicTacToeBoards behaves as if annotated with the @ApiClass from BoardsBase.
// Thus, the "resource" property will be "boards".
@Api(name = "tictactoe", version = "v1", resource = "scores")
class TicTacToeBoards extends BoardsBase {  }

dove TicTacToeBoards eredita il valore della proprietà resource boards da BoardsBase, sostituendo così l'impostazione della proprietà resource (scores) nella sua annotazione @Api. Ricorda che se una classe ha specificato la proprietà della risorsa nell'annotazione @Api, tutte le classi devono specificare la stessa impostazione nell'annotazione @Api. Questa tecnica di ereditarietà ti consente di ignorare la proprietà @Api.

Utilizzare l'ereditarietà @ApiReference

Per utilizzare questa funzionalità, è necessaria la seguente importazione:

import com.google.api.server.spi.config.ApiReference;

L'annotazione @ApiReference fornisce un modo alternativo per specificare l'annotazione ereditarietà. Una classe che utilizza @ApiReference per specificare un'altra classe con Le annotazioni @Api o @ApiClass si comportano come se fossero annotate con lo stesso proprietà. Ad esempio:

@Api(name = "tictactoe", version = "v1")
class TicTacToeBase {  }

// TicTacToeA behaves as if it has the same @Api annotation as TicTacToeBase
@ApiReference(TicTacToeBase.class)
class TicTacToeA {  }

Se vengono utilizzati sia l'eredità Java sia @ApiReference, le annotazioni ereditano solo tramite l'annotazione @ApiReference. Le annotazioni @Api e @ApiClass sulla classe ereditata tramite l'eredità Java vengono ignorate. Per esempio:

@Api(name = "tictactoe", version = "v1")
class TicTacToeBaseA {  }
@Api(name = "tictactoe", version = "v2")
class TicTacToeBaseB {  }

// TicTacToe will behave as if annotated the same as TicTacToeBaseA, not TicTacToeBaseB.
// The value of the "version" property will be "v1".
@ApiReference(TicTacToeBaseA.class)
class TicTacToe extends TicTacToeBaseB {  }

Sostituzione della configurazione ereditata

Sia che si tratti di un'ereditarietà della configurazione mediante l'ereditarietà Java o di @ApiReference, puoi eseguire l'override della configurazione ereditata utilizzando un nuovo criterio @Api Annotazione @ApiClass. Vengono sostituite solo le proprietà di configurazione specificate nella nuova annotazione. Le proprietà non specificate vengono comunque ereditate. Ad esempio:

@Api(name = "tictactoe", version = "v2")
class TicTacToe {  }

// Checkers will behave as if annotated with name = "checkers" and version = "v2"
@Api(name = "checkers")
class Checkers extends TicTacToe {  }

L'override dell'ereditarietà funziona anche per @ApiClass:

@Api(name = "tictactoe", version = "v1")
@ApiClass(resource = "boards", clientIds = { "c1" })
class Boards {  }

// Scores will behave as if annotated with resource = "scores" and clientIds = { "c1" }
@ApiClass(resource = "scores")
class Scores {  }

L'override funziona anche quando l'eredità avviene tramite @ApiReference:

@Api(name = "tictactoe", version = "v2")
class TicTacToe {  }

// Checkers will behave as if annotated with name = "checkers" and version = "v2"
@ApiReference(TicTacToe.class)
@Api(name = "checkers")
class Checkers {  }

Ereditare le annotazioni @ApiMethod

L'annotazione @ApiMethod può essere ereditata dai metodi sostituiti. Per esempio:

class TicTacToeBase {
  @ApiMethod(httpMethod = "POST")
  public Game setGame(Game game) {  }
}
@Api(name = "tictactoe", version = "v1")
class TicTacToe extends TicTacToeBase {
  // setGame behaves as if annotated with the @ApiMethod from TicTacToeBase.setGame.
  // Thus the "httpMethod" property will be "POST".
  @Override
  public Game setGame(Game game) {  }
}

Analogamente all'ereditarietà delle annotazioni @Api e @ApiClass, se vengono utilizzati più metodi che eseguono l'override a vicenda hanno @ApiMethod annotazioni, le singole proprietà possono eseguire l'override. Ad esempio:

class TicTacToeBase {
  @ApiMethod(httpMethod = "POST", clientIds = { "c1" })
  public Game setGame(Game game) {  }
}
@Api(name = "tictactoe", version = "v1")
class TicTacToe extends TicTacToeBase {
  // setGame behaves as if annotated with httpMethod = "GET" and clientIds = { "c1"}.
  @ApiMethod(httpMethod = "GET")
  @Override
  public Game setGame(Game game) {  }
}

Non esiste un'annotazione @ApiReference o un equivalente per i metodi, quindi Il campo @ApiMethod viene sempre ereditato tramite l'ereditarietà Java, non tramite @ApiReference.

Regole di ereditarietà e precedenza

Per sinotizzare la discussione precedente, la tabella seguente mostra l'ereditarietà regole e ordine di precedenza.

Annotazione/ereditarietà Regola
@Api Deve essere identico per tutte le classi.
@ApiClass Specificato per un corso per eseguire l'override delle proprietà @Api.
Ereditarietà Java La classe eredita @Api e @ApiClass dalla classe di base.
@ApiReference La classe eredita @Api e @ApiClass della classe a cui fa riferimento.
Utilizzo di @ApiReference su una classe (Java) che eredita da una classe base La classe eredita @Api e @ApiClass della classe di riferimento, non dalla classe base.

Casi d'uso comuni per l'ereditarietà delle annotazioni

Ecco alcuni esempi di casi d'uso tipici per l'ereditarietà:

Per il controllo delle versioni delle API:

@Api(name = "tictactoe", version = "v1")
class TicTacToeV1 {  }
@Api(version = "v2")
class TicTacToeV2 extends TicTacToeV1 {  }

Per le API multiclasse:

@Api(name = "tictactoe", version = "v1")
class TicTacToeBase {}
@ApiClass(resource = "boards")
class TicTacToeBoards extends TicTacToeBase {  }
@ApiClass(resource = "scores")
class TicTacToeScores extends TicTacToeBase {  }

Per testare versioni diverse della stessa API:

@Api(name = "tictactoe", version = "v1")
class TicTacToe {
  protected Foo someMethod() {
    // Do something real;
  }

  public Foo getFoo() {  }
}


@Api(version="v1test")
class TicTacToeTest extends TicTacToe {
  protected Foo someMethod() {
    // Stub out real action;
  }
}

dove someMethod potrebbe restituire risposte predeterminate, evitare chiamate con effetti collaterali, saltare una richiesta di rete o di datastore e così via.

Aggiunta dei corsi a web.xml

Dopo aver annotato i tuoi corsi, devi aggiungerli al file web.xml. L'esempio seguente mostra una singola classe:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <!-- Wrap the backend with Endpoints Frameworks v2. -->
    <servlet>
        <servlet-name>EndpointsServlet</servlet-name>
        <servlet-class>com.google.api.server.spi.EndpointsServlet</servlet-class>
        <init-param>
            <param-name>services</param-name>
            <param-value>com.example.skeleton.MyApi</param-value>
        </init-param>
    </servlet>
    <!-- Route API method requests to the backend. -->
    <servlet-mapping>
        <servlet-name>EndpointsServlet</servlet-name>
        <url-pattern>/_ah/api/*</url-pattern>
    </servlet-mapping>
</web-app>

Per aggiungere più corsi:

  1. Sostituisci <param-value>com.example.skeleton.MyApi</param-value> con nome della classe API.

  2. Aggiungi ogni corso all'interno dello stesso campo <param-value> separato da una virgola, Ad esempio:

    <param-value>com.example-company.example-api.Hello,com.example-company.example-api.Goodbye</param-value>