API Multiclass

Jika satu API sangat rumit, sebaiknya implementasikan dari beberapa class Java. Untuk membuat class yang berbeda menjadi bagian dari API yang sama, Anda harus:

Misalnya, dua class berikut adalah bagian dari tictactoe API:

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

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

Konfigurasi API ditentukan melalui properti anotasi @Api. Namun, untuk beberapa class dalam API yang sama, persyaratan @Api meluas di luar sekadar memiliki string name dan version yang sama dalam anotasi @Api untuk setiap class. Bahkan, API backend Anda tidak akan berfungsi jika ada perbedaan dalam konfigurasi API yang ditentukan dalam properti @Api class. Perbedaan apa pun pada properti @Api untuk class dalam API multiclass akan menghasilkan konfigurasi API yang "ambigu", yang tidak akan berfungsi di Framework Cloud Endpoints untuk App Engine.

Ada beberapa cara untuk membuat API multiclass yang tidak ambigu:

  • Pastikan secara manual bahwa semua class dalam satu API memiliki properti anotasi @Api yang sama persis.
  • Gunakan pewarisan anotasi melalui pewarisan Java. Dalam pewarisan ini, semua class dalam satu API mewarisi konfigurasi API yang sama dari class dasar yang dianotasi @Api umum.
  • Gunakan pewarisan anotasi melalui anotasi @ApiReference di semua class dalam satu API agar class tersebut mereferensikan konfigurasi API yang sama dari class yang dianotasi @Api umum.

Menggunakan @ApiClass untuk properti yang dapat berbeda antar-class

Untuk menggunakan fitur ini, Anda memerlukan impor berikut:

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

Meskipun semua properti dalam anotasi @Api harus cocok untuk semua class dalam API, Anda juga dapat menggunakan anotasi @ApiClass untuk menyediakan properti yang tidak perlu sama persis di antara class. Contoh:

// 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 {  }

dengan TicTacToeA membatasi akses menggunakan daftar yang diizinkan untuk client ID yang berisi client ID yang diizinkan, dan TicTacToeB tidak membatasi akses.

Semua properti yang disediakan oleh anotasi @ApiClass memiliki properti yang setara dalam anotasi @Api. Perhatikan bahwa properti setara @Api bertindak sebagai default seluruh API. Jika ada default seluruh API untuk properti yang sama, yang ditentukan dalam @Api, properti @ApiClass khusus class akan menggantikan default seluruh API.

Contoh berikut mengilustrasikan penggantian properti @Api oleh @ApiClass yang setara dengan class:

// 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 {  }

Pewarisan anotasi

Properti anotasi @Api dan @ApiClass dapat diwarisi dari class lain, dan setiap properti dapat diganti melalui pewarisan Java atau pewarisan @ApiReference

Menggunakan pewarisan Java

Class yang memperluas class lain dengan anotasi @Api atau @ApiClass berperilaku seolah-olah dianotasi dengan properti yang sama. Contoh:

@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 {  }

Anotasi hanya diwarisi melalui subclassing Java, bukan melalui penerapan antarmuka. Contoh:

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

Akibatnya, tidak ada dukungan untuk jenis pewarisan ganda apa pun anotasi framework.

Pewarisan juga berfungsi untuk @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 {  }

dengan TicTacToeBoards mewarisi nilai properti resource boards dari BoardsBase, sehingga mengganti setelan properti resource (scores) dalam anotasi @Api-nya. Ingat bahwa jika ada class yang telah menentukan properti resource dalam anotasi @Api, semua class harus menentukan setelan yang sama dalam anotasi @Api; teknik pewarisan ini memungkinkan Anda mengganti properti @Api tersebut.

Menggunakan pewarisan @ApiReference

Untuk menggunakan fitur ini, Anda memerlukan impor berikut:

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

Anotasi @ApiReference menyediakan cara alternatif untuk menentukan pewarisan anotasi. Class yang menggunakan @ApiReference untuk menentukan class lain dengan anotasi @Api atau @ApiClass berperilaku seolah-olah dianotasi dengan properti yang sama. Contoh:

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

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

Jika pewarisan Java dan @ApiReference digunakan, anotasi akan diwariskan melalui anotasi @ApiReference saja. Anotasi @Api dan @ApiClass pada class yang diwarisi melalui pewarisan Java akan diabaikan. Misalnya:

@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 {  }

Mengganti konfigurasi yang diwarisi

Baik mewarisi konfigurasi menggunakan pewarisan Java atau @ApiReference, Anda dapat mengganti konfigurasi yang diwarisi menggunakan anotasi @Api atau @ApiClass baru. Hanya properti konfigurasi yang ditentukan dalam anotasi baru yang akan diganti. Properti yang tidak ditentukan tetap diwarisi. Contoh:

@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 {  }

Penggantian pewarisan juga berfungsi untuk @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 {  }

Penggantian juga berfungsi saat mewarisi melalui @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 {  }

Mewarisi anotasi @ApiMethod

Anotasi @ApiMethod dapat diwarisi dari metode yang diganti. Misalnya:

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) {  }
}

Serupa dengan pewarisan anotasi @Api dan @ApiClass, jika beberapa metode yang saling mengganti memiliki anotasi @ApiMethod, setiap properti dapat diganti. Contoh:

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) {  }
}

Tidak ada anotasi @ApiReference atau yang setara untuk metode, sehingga @ApiMethod selalu diwarisi melalui pewarisan Java, bukan melalui @ApiReference.

Aturan pewarisan dan prioritas

Untuk meringkas diskusi sebelumnya, tabel berikut menunjukkan aturan pewarisan dan urutan prioritas.

Anotasi/pewarisan Aturan
@Api Harus sama untuk semua class.
@ApiClass Ditentukan untuk class guna mengganti properti @Api.
Pewarisan Java Class mewarisi @Api dan @ApiClass dari class dasar.
@ApiReference Class mewarisi @Api dan @ApiClass dari class yang dirujuk.
Menggunakan @ApiReference pada class (Java) yang diwarisi dari class dasar Class mewarisi @Api dan @ApiClass dari class yang direferensikan, bukan dari class dasar.

Kasus penggunaan umum untuk pewarisan anotasi

Berikut adalah contoh kasus penggunaan umum untuk pewarisan:

Untuk pembuatan versi API:

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

Untuk API multiclass:

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

Untuk menguji berbagai versi API yang sama:

@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;
  }
}

dengan someMethod yang mungkin menampilkan respons yang telah ditentukan sebelumnya, hindari panggilan dengan efek samping, lewati permintaan jaringan atau datastore, dan sebagainya.

Menambahkan class ke web.xml

Setelah menganotasi class, Anda harus menambahkannya ke file web.xml. Contoh berikut menunjukkan satu class:

<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>

Untuk menambahkan beberapa kelas:

  1. Ganti <param-value>com.example.skeleton.MyApi</param-value> dengan nama class API Anda sendiri.

  2. Tambahkan setiap class di dalam kolom <param-value> yang sama ini yang dipisahkan dengan koma, misalnya:

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