단일 API가 특히 복잡한 경우, 여러 자바 클래스에서 이를 구현해야 할 수 있습니다. 동일 API를 여러 클래스 부분으로 만들려면 다음을 수행해야 합니다.
- 각 클래스의
@Api주석에서name및version문자열을 동일하게 지정합니다. - 클래스 API를
web.xml에서 쉼표로 구분된 목록으로 추가합니다.
예를 들어 다음 두 개의 클래스는 모두 tictactoe API에 포함됩니다.
@Api(name = "tictactoe", version = "v1")
class TicTacToeA { … }
@Api(name = "tictactoe", version = "v1")
class TicTacToeB { … }
API 구성은 @Api 주석 속성을 통해 지정됩니다.
하지만 동일 API에 여러 클래스가 있는 경우에는 단순히 각 클래스의 @Api 주석에서 동일한 name 및 version 문자열을 사용하는 것 외에도 @Api에 대한 요구사항이 더 있습니다. 실제로 클래스의 @Api 속성에 지정된 API 구성이 조금만 달라도 백엔드 API가 작동하지 않습니다. 멀티클래스 API에서는 클래스의 @Api 속성이 조금만 달라도 API 구성이 '모호해지기' 때문에 App Engine용 Cloud Endpoints Frameworks에서 API가 작동하지 않게 됩니다.
모호하지 않은 멀티클래스 API를 만들기 위한 방법에는 몇 가지가 있습니다.
- 단일 API의 모든 클래스가 정확히 동일한
@Api주석 속성을 갖는지 직접 확인합니다. - 자바 상속성을 통해 주석 상속성을 사용합니다.
이 상속성을 사용할 경우 단일 API의 모든 클래스가 공통의
@Api주석이 지정된 기본 클래스로부터 동일한 API 구성을 상속합니다. - 단일 API의 모든 클래스에서
@ApiReference주석을 통한 주석 상속성을 사용하여 각 클래스가 공통의@Api주석이 지정된 클래스에서 동일한 API 구성을 참조하도록 합니다.
클래스 간 달라질 수 있는 속성에 @ApiClass 사용
이 기능을 사용하려면 다음과 같은 가져오기가 필요합니다.
import com.google.api.server.spi.config.ApiClass;
@Api 주석의 모든 속성은 API의 모든 클래스에서 일치해야 하지만 @ApiClass 주석을 추가로 사용하면 클래스 간에 정확히 동일할 필요가 없는 속성을 제공할 수 있습니다. 예를 들면 다음과 같습니다.
// 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 { … }
여기에서 TicTacToeA는 허용되는 클라이언트 ID가 포함된 클라이언트 ID 허용 목록을 사용해 액세스를 제한하는 반면 TicTacToeB는 액세스를 제한하지 않습니다.
@ApiClass 주석에서 제공되는 모든 속성은 @Api 주석에서 상응하는 속성을 갖습니다. @Api의 상응 속성은 API 전체의 기본값으로 사용됩니다. 동일한 속성에 대해 @Api에 지정된 API 전체 기본값이 있는 경우에는 클래스별 @ApiClass 속성이 API 전체 기본값을 재정의합니다.
다음 예시에서는 @Api 속성이 클래스별 @ApiClass의 상응 속성에 의해 재정의되는 경우를 보여줍니다.
// 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 { … }
주석 상속성
@Api 및 @ApiClass 주석 속성은 다른 클래스로부터 상속될 수 있으며, 자바 상속성 또는 @ApiReference 상속성을 통해 개별 속성이 재정의될 수 있습니다.
자바 상속성 사용
@Api 또는 @ApiClass 주석이 지정된 다른 클래스를 확장하는 클래스는 마치 동일한 속성의 주석이 지정된 것처럼 동작합니다. 예를 들면 다음과 같습니다.
@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 { … }
주석은 인터페이스 구현이 아니라 자바 하위 클래스를 통해서만 상속됩니다. 예를 들면 다음과 같습니다.
@Api(name = "tictactoe", version = "v1")
interface TicTacToeBase { … }
// Does *not* behave as if annotated.
class TicTacToeA implements TicTacToeBase { … }
따라서 프레임워크 주석에 대해서는 어떠한 종류의 다중 상속성도 지원되지 않습니다.
상속성은 @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 { … }
여기서 TicTacToeBoards는 BoardsBase로부터 resource 속성 값 boards를 상속하므로 해당 클래스의 @Api 주석에 포함된 resource 속성 설정(scores)이 재정의됩니다. 어떤 클래스의 @Api 주석에 resource 속성이 지정되었으면 모든 클래스가 @Api 주석에서 동일한 설정을 지정해야 합니다. 이러한 상속성 기술로 @Api 속성을 재정의할 수 있습니다.
@ApiReference 상속성 사용
이 기능을 사용하려면 다음과 같은 가져오기가 필요합니다.
import com.google.api.server.spi.config.ApiReference;
@ApiReference 주석은 주석 상속성을 지정하기 위한 또 다른 방법을 제공합니다. @ApiReference를 사용해 @Api 또는 @ApiClass 주석이 있는 다른 클래스를 지정하는 클래스는 마치 동일한 속성의 주석이 지정된 것처럼 동작합니다. 예를 들면 다음과 같습니다.
@Api(name = "tictactoe", version = "v1")
class TicTacToeBase { … }
// TicTacToeA behaves as if it has the same @Api annotation as TicTacToeBase
@ApiReference(TicTacToeBase.class)
class TicTacToeA { … }
자바 상속성과 @ApiReference를 모두 사용하는 경우 주석 상속은 @ApiReference 주석을 통해서만 이루어집니다. 자바 상속성을 통해 상속되는 클래스의 @Api 및 @ApiClass 주석은 무시됩니다. 예를 들면 다음과 같습니다.
@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 { … }
상속된 구성 재정의
자바 상속성을 사용해 구성을 상속하든, 혹은 @ApiReference를 사용해 구성을 상속하든 상관없이 새로운 @Api 또는 @ApiClass 주석을 사용해 상속된 구성을 재정의할 수 있습니다. 새로운 주석에 지정된 구성 속성만 재정의됩니다. 지정되지 않은 속성은 계속 상속됩니다.
예를 들면 다음과 같습니다.
@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 { … }
상속성 재정의는 @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 { … }
또한 @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 { … }
@ApiMethod 주석 상속
@ApiMethod 주석은 재정의된 메서드로부터 상속될 수 있습니다. 예를 들면 다음과 같습니다.
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) { … }
}
@Api 및 @ApiClass 주석 상속성과 마찬가지로, 서로를 재정의하는 여러 메서드에 @ApiMethod 주석이 포함된 경우 개별 속성을 재정의할 수 있습니다. 예를 들면 다음과 같습니다.
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) { … }
}
메서드의 경우 @ApiReference 주석 또는 그에 상응하는 주석이 없으므로 @ApiMethod는 항상 @ApiReference가 아니라 자바 상속성을 통해 상속됩니다.
상속성 및 우선 순위 규칙
앞의 내용을 요약해서, 다음 테이블은 상속성 규칙과 우선 순위를 보여줍니다.
| 주석/상속성 | 규칙 |
|---|---|
@Api |
모든 클래스에 대해 동일해야 합니다. |
@ApiClass |
특정 클래스가 @Api 속성을 재정의하도록 지정합니다. |
| 자바 상속성 | 클래스가 기본 클래스의 @Api 및 @ApiClass를 상속합니다. |
@ApiReference |
클래스가 참조 클래스의 @Api 및 @ApiClass를 상속합니다. |
기본 클래스로부터 상속하는 클래스(자바)에서 @ApiReference 사용 |
클래스가 기본 클래스로부터 상속하지 않고 참조 클래스의 @Api 및 @ApiClass를 상속합니다. |
주석 상속성의 일반적인 사용 사례
다음은 상속성의 일반적인 사용 사례입니다.
API 버전 관리:
@Api(name = "tictactoe", version = "v1")
class TicTacToeV1 { … }
@Api(version = "v2")
class TicTacToeV2 extends TicTacToeV1 { … }
다중 클래스 API:
@Api(name = "tictactoe", version = "v1")
class TicTacToeBase {}
@ApiClass(resource = "boards")
class TicTacToeBoards extends TicTacToeBase { … }
@ApiClass(resource = "scores")
class TicTacToeScores extends TicTacToeBase { … }
동일 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;
}
}
여기서 someMethod는 미리 결정된 응답을 반환하고, 부작용이 있는 호출을 방지하고, 네트워크 또는 데이터 저장소 요청을 건너뛰는 등의 작업을 수행합니다.
web.xml에 클래스 추가
클래스에 주석을 지정한 후에는 이를 web.xml 파일에 추가해야 합니다. 다음 예에서는 단일 클래스를 보여줍니다.
여러 클래스를 추가하려면 다음 안내를 따르세요.
<param-value>com.example.skeleton.MyApi</param-value>를 해당하는 API 클래스 이름으로 바꿉니다.동일한
<param-value>필드 내에 각 클래스를 쉼표로 구분해서 추가합니다. 예를 들면 다음과 같습니다.<param-value>com.example-company.example-api.Hello,com.example-company.example-api.Goodbye</param-value>