※この記事はLiferayコミュニティブログに投稿された、_Creating Headless APIs (Part 1)_を翻訳したものです。
はじめに
最近私は、Liferayの新しいヘッドレスAPIを用いた開発を試しています。具体的にはヘッドレス・デリバリーとヘッドレス・ユーザー管理モジュールを活用したReactベースのSAPです。4回に渡って実装の内容を紹介していきますが、今回は、REST Builderツールを使用して独自のヘッドレスAPIを作成する方法を紹介します。
ここで次のような疑問を抱くかも知れません。
「なぜ伝統的なJAX-RSに基づく独自のRESTではなく、REST Builderを使用するのか?」
LiferayのREST Builderは、単にエンドポイントを公開するアプリケーションをビルドするだけではありません。次の追加機能も提供してくれます。:
- Liferayの認証パイプラインとの統合
- LiferayのCORSの扱いとの統合
- Liferayの検索、フィルタリング、ページングなどとの統合をサポートするためのヘッドレスファシリティ
- 呼び出し側リクエストに対するJSONまたはXMLの生成機能
- 近くリリースされる LiferayのGraphQLエンドポイントとの統合により、REST Builder APIのカスタマイズなしでのGraphQLを経由した利用
- モバイルおよびSPAアプリケーション開発者への一貫性の担保。
これら全部を利用する必要があるわけではなく、適材適所でこれら機能を利用してください。
ブログシリーズの初回を飾る当記事では、新しいREST Builderを使用するためのプロジェクトをセットアップし、エントリポイントを定義するYAMLファイルの主要箇所を紹介します。当記事は長くなるため、いくつかのパートに分けて、まずはサービスパス(エントリポイント)の定義から始め、サービスの構築を説明してきます。
事前作業
作業を始める前に、REST Builderの使い方に関するLiferayの公式ドキュメントに目を通してください。記事を読むのにはそれほど時間はかかりませんので、読み終えたらまた当記事へ戻ってきてください。
プロジェクトの開始
次のコマンドを実行して作業用プロジェクトを作成します:
blade init -v 7.2 vitamins
今回はプロジェクトの構成をイメージしやすくするため、プロジェクトを「ビタミン」と名付けました。このプロジェクトはビタミンとミネラルで構成され、それらはWebコンテンツよりも多くのビタミンとミネラルを保持している必要があります。そのためヘッドレスREST層(REST Builder)と併せて、カスタムサービス層(Service Builder)が必要になります。
注:この先、gradle.propertiesでターゲットプラットフォームが有効になっているものとします。すでに設定が済んでいる場合は問題なく次へ読み進めてください。私はターゲットプラットフォームを使用しているため、build.gradleファイル内にバージョンを含めません。
次にプロジェクトをIDEにロードし、次の手順に従ってheadless-vitamins-implモジュール(後に説明)でbuild.gradleファイルを編集します:https://portal.liferay.dev/docs/7-2/reference/-/knowledge_base/r/rest-builder-gradle-plugin
注:参照記事に明記されていない注意点として、Liferay Gradle Workspaceを使用している場合、該当ワークスペースが生成するビルドスクリプトはheadress-<名前>-impl
モジュール内のbuild.gradle
ファイルに入り、settings.gradle
ファイルまたはルートレベルのbuild.gradle
ファイルには入りません。このケースでビルドスクリプトをsettings.gradle
ファイルへ置こうとすると、org.gradle.initialization.DefaultSettings_Decorated cannot be cast to org.gradle.api.Project
といった予期せぬエラーが発生します。もしこれが発生した場合は、あなたのREST Builderプラグインが正しくないファイルにリストされていることを意味します。
headless-vitamins-impl
モジュール内で./gradlew tasks
コマンドを実行することで、実際にREST Builderが利用可能であることを確認できます:
$ ./gradlew tasks
> Task :tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
buildCSS - Build CSS files.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildLang - Runs Liferay Lang Builder to translate language property files.
buildNeeded - Assembles and tests this project and all projects it depends on.
buildREST - Runs Liferay REST Builder.
...省略...
モジュール一式が必要となるため、ワークスペースのmodules/headless-vitamins
フォルダ(ヘッドレスモジュールを一緒にまとめるためにこのサブディレクトリを作成しました)にheadless-vitamins-api
、headless-vitamins-impl
、headless-vitamins-client
、およびheadless-vitamins-test
を作成します。参照ドキュメンテーションではこれら追加モジュールの作成には触れていませんが、後に示す通り、これらは必要になってきます。
$ cd modules/headless-vitamins
$ blade create -t api -v 7.2 -p com.dnebinger.headless.vitamins headless-vitamins-api
Successfully created project headless-vitamins-api in vitamins/modules/headless-vitamins
$ blade create -t api -v 7.2 -p com.dnebinger.headless.vitamins headless-vitamins-impl
Successfully created project headless-vitamins-impl in vitamins/modules/headless-vitamins
$ blade create -t api -v 7.2 -p com.dnebinger.headless.vitamins headless-vitamins-client
Successfully created project headless-vitamins-client in vitamins/modules/headless-vitamins
$ blade create -t api -v 7.2 -p com.dnebinger.headless.vitamins headless-vitamins-test
Successfully created project headless-vitamins-test in vitamins/modules/headless-vitamins
上記コマンドでモジュールを作成する際に、タイプとしてapi
を指定したため、いくつかの不要なパッケージやjavaファイルも生成されます。これらをクリーンアップするには、少々時間を要します。また、headless-vitamins-test
ディレクトリのsrc/mai
ディレクトリを src/testIntegration
へリネームする必要があります。
このプロジェクトはREST Builderがいくつかの統合テストケースを生成しますが、それを機能させるには適切なディレクトリが必要です。
Liferayのバンドルの標準命名規則に従うため、bnd.bndファイルはcom.dnebinger.headless.vitamins.api
およびcom.dnebinger.headless.vitamins.impl
シンボリック名などで更新されます。build.gradle
ファイルには多くの追加が必要になりますが、もうひと息です。
サービスの定義
ここから徐々に楽しくなってきます。サービスエンドポイントを定義するためのYAMLファイルを作成しましょう。この作業が初めての場合、気が遠くなると感じるかもしれません。
まずは単純な作業として。headless-vitamins-impl
内にrest-config.yaml
ファイルを追加する必要があります。
apiDir: "../headless-vitamins-api/src/main/java"
apiPackagePath: "com.dnebinger.headless.vitamins"
application:
baseURI: "/headless-vitamins"
className: "HeadlessVitaminsApplication"
name: "dnebinger.Headless.Vitamins"
author: "Dave Nebinger"
clientDir: "../headless-vitamins-client/src/main/java"
testDir: "../headless-vitamins-test/src/testIntegration/java"
これはLiferayのヘッドレスが機能するのに必要な、あなたの作成した要素群を一つに構成したものです。最後の2つのエントリでクライアントとテストを指します。したがって、この作業は先に終わらせます。
次にrest-openapi.yaml
ファイルを扱います。このファイルもheadless-vitamins-impl
モジュール内に作成されるものです。一度にすべてを捨てるのではなく、ここでは順を追って詳細を理解していきます。すべてのファイル構成はこのリポジトリで確認できます。
各OpenAPI YAMLファイルはMeta、Paths(エンドポイント)およびReusable Components(型定義)の3つのセクションから成り、今回作成したものと違いはありません。
私のメタセクションは次の通りです:
openapi: 3.0.1
info:
title: "Headless Vitamins"
version: v1.0
description: "API for accessing Vitamin details."
ここまで順調に進んでいます。
注:単純なテキストエディタはYAMLファイルの編集に向きません。特に、行の折り返しにおける適切なインデント処理に難があります。もし使い慣れたエディタをお持ちでなければ、https://editor.swagger.io/で入手可能なSwaggerのアウトラインツールがおすすめです。このツールは適切なインデント処理だけでなく、OpenAPI YAML形式のファイルを扱う際に非常に役立つコード補完機能も有しています。
型の定義
次に、今回作成した再利用可能なコンポーネントを共有します。これらは単体で機能するものではありませんが、後にPathsをカバーする際の負担を軽くします。
私の主要型と「ビタミン」の型:
components:
schemas:
Vitamin:
description: Contains all of the data for a single vitamin or mineral.
properties:
name:
description: The vitamin or mineral name.
type: string
id:
description: The vitamin or mineral internal ID.
type: string
chemicalNames:
description: The chemical names of the vitamin or mineral if it has some.
items:
type: string
type: array
properties:
description: The chemical properties of the vitamin or mineral if it has some.
items:
type: string
type: array
group:
description: The group the vitamin or mineral belongs to, i.e. the B group or A group.
type: string
description:
description: The description of the vitamin or mineral.
type: string
articleId:
description: A journal articleId if there is a web content article for this vitamin.
type: string
type:
description: The type of the vitamin or mineral.
enum: [Vitamin, Mineral, Other]
type: string
attributes:
description: Health properties attributed to the vitamin or mineral.
items:
type: string
type: array
risks:
description: Risks associated with the vitamin or mineral.
items:
type: string
type: array
symptoms:
description: Symptoms associated with the vitamin or mineral deficiency.
items:
type: string
type: array
creator:
$ref: "#/components/schemas/Creator"
type: object
上記はYAMLの書式です。インデントは階層を表し、より深いインデントの行がその子となり、同階層の行は兄弟を意味します。
「ビタミン」の型は多くのプロパティを持ちます。プロパティは name や id といった単純なものから、より複雑なものまでさまざまです。型プロパティはString
ですが、可能な値の列挙によって制限されます。クリエイターはこのファイル内における別オブジェクト($ref
がこれに当たります)への参照です。
同一ファイル内に$ref
がある場合、参照を含める必要があることを意味します。Liferayのheadless-delivery
ファイルからコピーした「ビタミン」のクリエイター型は次のとおりです:
Creator:
description: Represents the user account of the content's creator/author. Properties follow the [creator](https://schema.org/creator) specification.
properties:
additionalName:
description: The author's additional name (e.g., middle name).
readOnly: true
type: string
familyName:
description: The author's surname.
readOnly: true
type: string
givenName:
description: The author's first name.
readOnly: true
type: string
id:
description: The author's ID.
format: int64
readOnly: true
type: integer
image:
description: A relative URL to the author's profile image.
format: uri
readOnly: true
type: string
name:
description: The author's full name.
readOnly: true
type: string
profileURL:
description: A relative URL to the author's user profile.
format: uri
readOnly: true
type: string
type: object
型の説明は以上です。
まとめ
まとめるには早すぎますか?確かにまだ作業は未完了ですね!次のパートはすでに記事にしてあるのでご安心ください。
このパートでは、カスタムヘッドレスサービスと必要なモジュール群を備えた、新しい Liferay Gradle Workspace の作成方法を紹介しました。
また、OpenAPIのYAMLファイルをはじめ、再利用可能なコンポーネントについて理解を深めるために、Pathセクションを飛ばしつつMetaセクションに触れ、「ビタミン」プロジェクトとクリエイターオブジェクトを定義しました。
次回はPaths(エントリポイント)を洗い出していきます
それではまた次のパートでお会いしましょう!