REST Builderを使用したAPIの作成と実装
RESTビルダーを使用すると、構築したいAPIを定義でき、RESTビルダーはフレームワークとエンドポイントを提供します。
サンプルREST APIをデプロイする
RESTビルダーの動作を確認するために、カタログ内のIDによってダミー製品を取得するサンプルAPIをデプロイできます。 この簡単な例がどのように機能するかを理解したら、独自のアプリケーション用のAPIを作成できます。
新しいLiferay インスタンスを起動し、以下を実行します。
docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.132-ga132
http://localhost:8080 で Liferay にサインインしてください。 メールアドレス test@liferay.com とパスワード test を使用してください。 プロンプトが表示されたら、パスワードを learn に変更してください。
次に、以下の手順に従います。
-
.zipアーカイブをダウンロードして解凍します。このアーカイブには Acme Foo API が含まれています。curl https://resources.learn.liferay.com/examples/liferay-r3b2.zip -Ounzip liferay-r3b2.zip -
サンプルをビルドしてデプロイします。
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)注記このコマンドは、デプロイされたjarファイルをDockerコンテナの/opt/liferay/osgi/modulesにコピーするのと同じです。
-
apiとimplバンドルの両方について、Dockerコンテナコンソールでデプロイを確認してください。com.acme.headless.r3b2.api_1.0.0 を開始しました com.acme.headless.r3b2.impl_1.0.0 を開始しました -
DXPインスタンスにログインし、 グローバルメニュー (
)→ コントロールパネル → Gogo Shellに移動します。 -
Gogo Shellのプロンプトで、次のコマンドを入力します。
jaxrs:チェックこのページには、新しくデプロイされた API
Liferay.Headless.R3B2を含む、インストールされているすべての JAX-RS バンドルが一覧表示されます。 APIはデプロイされ、呼び出し可能な状態になりました。
-
ターミナルから以下のコマンドを実行し、
{fooId}の部分を 1 から 3 の間の数値に置き換えて、API をテストしてください。curl -u 'test@liferay.com:learn' "http://localhost:8080/o/headless-r3b2/v1.0/foo/{fooId}"このクエリは、対応する製品のID、名前、説明をJSONオブジェクトにラップして返します。
{ "説明": "普遍的な真理は超越的でなければならない。"、 "id": 1、 "name": "Truth" }
おめでとうございます。新しいREST APIのデプロイと使用に成功しました。
REST Builderで生成されたAPIをご覧いただいたところで、次はそれがどのように動作するのかを理解しましょう。
初期設定
Liferayワークスペースプロジェクトに impl と api モジュールを作成します。 impl モジュールの build.gradle ファイルは、REST Builder をプラグインとしてインストールおよび適用する必要があります。
buildscript {
dependencies {
classpath group: "com.liferay", name: "com.liferay.gradle.plugins.rest.builder", version: "1.1.32"
}
repositories {
maven {
url "https://repository-cdn.liferay.com/nexus/content/groups/public"
}
}
}
apply plugin: "com.liferay.portal.tools.rest.builder"
dependencies {
compileOnly グループ: "com.liferay.portal"、名前: "release.dxp.api"
compileOnly プロジェクト(":headless-r3b2-api")
}
両方のモジュールの build.gradle ファイルもポータル リリースへの依存関係を宣言する必要があります。
YAML設定
まず最初に行うべきことは、REST Builderの設定ファイルを作成することです。 impl モジュールのルートフォルダに、次の 2 つのファイルを追加します。 rest-config.yaml および rest-openapi.yaml。 これらのファイルには、REST BuilderがAPIの足場となるコードを生成するために必要なすべての情報が含まれている必要があります。
REST Builder構成を追加する
REST Builder の設定は rest-config.yaml ファイルにあります。 これは以下のフィールドを定義します。
apiDir: Javaソースコードフォルダ
apiPackagePath: REST Builder がすべてのモジュールにわたってコードを生成する開始 Java パッケージ パス
baseURI: このプロジェクト内のすべてのAPIのコンテキストURL
className: ルートリソースクラスのJavaクラス名(JAX-RSで使用)
javaEEPackage: コード生成に使用する名前空間。 この名前空間 は、API をデプロイする Liferay のバージョンと 一致する必要があります。 デフォルトでは、REST Builder は Java EE 名前空間 (javax ) を使用してコードを生成します。 Jakartaに移行した最新バージョンのLiferayを使用している場合は、Jakarta EE名前空間を使用するために、値を jakarta に設定してください。
名前: API の JAX-RS 名
以下の構造を使用して、これらのフィールドを定義します。
apiDir: "../headless-r3b2-api/src/main/java"
apiPackagePath: "com.acme.headless.r3b2"
application:
baseURI: "/headless-r3b2"
className: "HeadlessR3B2Application"
名前: "Liferay.Headless.R3B2"
作者: "アミッタイの息子ヨナ"
クライアントディレクトリ: "../headless-r3b2-client/src/main/java"
testDir: "../headless-r3b2-test/src/testIntegration/java"
OpenAPI設定に情報ブロックを追加する
次に、 rest-openapi.yaml ファイルを開いて、API の設定を開始します。
最初に追加するセクションは情報ブロックです。
info:
description:
"Foo を返す API。"
ライセンス:
名前: "Apache 2.0"
URL: "http://www.apache.org/licenses/LICENSE-2.0.html"
タイトル: "Headless R3B2"
バージョン: v1.0
openapi: 3.0.1
ここで定義されている バージョン フィールドは、Liferay インスタンス内で API パスが公開されると URL の一部になります。
必要なスキーマを定義する
次に、 コンポーネント ブロックで、エンティティのスキーマを定義します。 REST Builderは、ここで定義した内容を使用して、これらのエンティティを表す対応するJava Beanを作成します。
表現したいエンティティごとに、 スキーマ ブロックを定義します。
コンポーネント:
スキーマ:
Foo:
プロパティ:
説明:
タイプ: 文字列
ID:
フォーマット: int64
タイプ: 整数
名前:
タイプ: 文字列
タイプ: オブジェクト
Goo:
プロパティ:
説明:
タイプ: 文字列
fooId:
フォーマット: int64
タイプ: 整数
id:
フォーマット: int64
タイプ: 整数
名前:
タイプ: 文字列
この例では、 Foo というスキーマが、この API を使用する上で重要なデータを表しています。 Goo エンティティは、 fooId を使用して Foo にリンクされています。 スキーマでサポートされているデータ型の一覧については、 OpenAPI 仕様 を参照してください。
スキーマ定義によって、REST Builderが生成するクラス名(リソースファイル内のスキャフォールディングやテンプレートを含む)が決まります。 上記のスキーマは Foo および Barと呼ばれているため、実装ロジックは FooResourceImpl および GooResourceImpl クラスに属します。
APIを定義する
最後に、 パス ブロックを追加します。 これには、REST Builderで実装予定のすべてのAPIを含める必要があります。 以下は、パスブロックのごく一部です。
パス:
"/foo":
get:
# get と post の操作はここに記述します。 完全なソースコードについては、プロジェクトを参照してください。
# ...
"/foo/{fooId}":
get:
operationId: getFoo
# ...
レスポンス:
200:
コンテンツ:
application/json:
スキーマ:
$ref: "#/components/schemas/Foo"
application/xml:
スキーマ:
$ref: "#/components/schemas/Foo"
# get、patch、put などの他の操作をここに配置します。 完全なソースコードについては、プロジェクトを参照してください。
"/foo/{fooId}/goos":
get:
operationId: getFooGoosPage
# これはFooとGoosの関係です。
# ここにGETおよびPOST操作を記述してください。
# ...
"/goo/{gooId}":
delete:
operationId: deleteGoo
# 必要に応じて他のエンティティに操作を配置します。
get、 post、 put、 patch、および delete など、さまざまな種類のリクエストのパスを追加できます。
パス(foo/{fooId} )は、このAPI(getFoo)が、URLの末尾にこのパス文字列を追加することでアクセスできることを示しています(このURLには、rest-config.yamlファイルに指定された baseURIおよびversionの値も含まれます)。 例えば、この例の API には、完全な URL を介してアクセスします: localhost:8080/o/headless-r3b2/v1.0/foo/{fooId}。
fooId に代入した値は、一致する名前のパラメータとして使用されます。
各パスには、パラメータブロックの下(かつgetブロック内)にresponsesブロックがあり、そこには少なくとも成功した呼び出し(200レスポンスで示される)に対するレスポンスが定義されています。
この レスポンス ブロックは、呼び出しが成功すると Product が返されることを指定します。 文字列 #/components/schemas/Foo は、同じファイルで以前に定義されたスキーマを参照し、REST Builder が Foo スキーマをこの API の戻り値の型として使用できるようにします。
最後に、 タグ 定義を、 レスポンス ブロックの下に追加します。
タグ: ["Foo"]
このタグは、REST Builderがスキャフォールディングコードに注釈を付ける際に、生成されるドキュメントに追加される情報を指定します。 タグ名は、スキーマ名と一致させる必要があります。
完全なリファレンスについては、以前ダウンロードした rest-openapi.yaml ファイルを参照してください。
また、関係性をどのように表現できるかを示すために、 Goo オブジェクトもあります。Goo は fooId に関連付けられているという意味で Foo と関連しています。
REST Builderを実行する
REST Builder がほとんどの作業を実行するために必要なすべての構成を追加したので、 impl モジュール内から次のコマンドを実行して、 buildREST Gradle タスクを実行します。
../gradlew buildREST
REST Builder は、設定を使用して、 api と impl クラスの両方にスキャフォールディング コードと、実装ロジックを追加できる Java クラスを生成します。
GraphQLエンドポイントコードとJAX-RSアプリケーションコードは、それぞれ graphql と jaxrs パッケージで生成されます。 独自の API 実装は、 リソース パッケージ内の適切な *ResourceImpl クラスに追加されます。
実装ロジックを追加
最後のステップは、定義した各APIのロジックを定義することです。 impl モジュール内で、 rest-openapi.yaml で定義したスキーマ名に基づいて、実装が配置される Java リソース クラスを見つけます (この例では、 FooResourceImpl.java と GooResourceImpl.java)。
実装用のクラスの場所は、 rest-config.yaml に定義した値によって決まります。 そのパスをたどり、その中の ファイルで apiPackagePathinternal/resource/<version>/ に移動します。 この例と同じパスを使用した場合、ファイルは src/main/java/com/acme/headless/r3b2/internal/resource/v1_0/ 内にあります。
実装クラス ([SchemaName]ResourceImpl) は、基底クラス (Base[SchemaName]ResourceImpl ) の隣にあります。 実装クラスを開きます。 これは単なる例なので、この実装では事前にデータが入力された HashTableを使用し、 getFoo メソッドは、一致する fooId を持つ HashTable からの積を返します。 完全な実装については、プロジェクト内の FooResourceImpl.java を参照してください。
@Override
public Foo getFoo(Integer fooId) {
return _foos.get(fooId);
}
このメソッドは、特別な JAX-RS アノテーションを使用して定義されている基底クラス (Base[SchemaName]ResourceImplで定義されている基底メソッドをオーバーライドします。
リクエストを完了するために、任意のビジネスロジックを追加できます。 REST Builderは、スキーマで定義したオブジェクトのデフォルトコンストラクターのみを作成します。 このビジネスロジックの例では、オブジェクトを作成し、そのオブジェクトに値を追加します(rest-openapi.yaml でのパラメータの定義に基づいて)。
Foo foo1 = new Foo() {
{
description = "普遍的な真理は超越的でなければならない。";
id = 1L;
name = "真理";
}
};
Goo のロジックは似ていますが、この場合は Foo オブジェクトが複数の Gooを含むことができるため、複数の Gooが返されます。 オブジェクトのコレクションを返す場合は、ページネーションに対応したオブジェクトである Page を使用する必要があります。
@Override
public Page<Goo> getFooGoosPage(Long fooId) {
List<Goo> goos = new ArrayList<>();
for (Goo goo : _goos.values()) {
if (Objects.equals(fooId, goo.getFooId())) {
goos.add(goo);
}
}
return Page.of(goos);
}
GraphQL名前空間を追加する
Liferayは、GraphQLアプリケーション向けの名前空間設定をサポートしています。 名前空間を使用すると、特定のアプリケーションにおけるクエリ、ミューテーション、および型をグループ化できます。 名前空間を指定することで、異なるアプリケーションで同じスキーマを重複して使用することも可能です。
Liferay アプリケーションで GraphQL を使用する方法の詳細については、 GraphQL API の利用 を参照してください。
GraphQL名前空間を追加して使用するには、以下の手順に従ってください。
-
アプリケーションの
implモジュールでrest-config.yamlファイルを開く。 -
graphQLNamespaceフィールドに、目的の名前空間名を追加します。graphQL名前空間: "<namespace name>" -
目的のクエリまたはミューテーションオブジェクトの1つ下の階層に名前空間を追加します。
クエリ{ <namespace name> { ... } } -
REST Builderを実行して、指定されたすべてのクエリとミューテーションをネームスペースに公開します。
GraphQL拡張機能内の名前空間には、 GraphQLContributor インターフェースを使用してアクセスすることもできます。 getGraphQLNamespace メソッドを実装して、目的の名前空間名を返します。
public class MyGraphQLContributor implements GraphQLContributor {
...
@Override
public String getGraphQLNamespace() {
return "<namespace name>";
}
...
}
GraphQL拡張機能では、名前空間はデフォルトで無効になっています。
結論
おめでとう! これで、REST Builder を使用した新しい API の実装の基本を理解し、DXP に新しい API を追加することができました。