ハイパーメディア対応スクリプティング

カーソン・グロス

RESTの制約セットへの最後の追加は、3.5.3セクション(図5-8)のオンデマンドコードスタイルから来ています。RESTでは、アプレットやスクリプトの形でコードをダウンロードして実行することにより、クライアントの機能を拡張できます。これにより、事前実装が必要な機能が減り、クライアントが簡略化されます。展開後に機能をダウンロードできるようにすると、システムの拡張性が向上します。ただし、可視性が低下するため、REST内ではオプションの制約にすぎません。

--ロイ・フィールディング - 表現状態転送(REST)

#スクリプティングとWeb

ハイパーメディア主導のアプリケーションでは、人気のSPAアプローチとは対照的に、アプリケーションをハイパーメディア主導で構築する方法について説明します。SPAアプローチでは、アプリケーションはJavaScriptで、ネットワークレベルではRPC主導です。

HDAの記事では、スクリプティングについて簡単に説明しています。

HDAでは、ハイパーメディア(HTML)がアプリケーション構築の主要な手段です。つまり

スクリプティングは既存のハイパーメディア(HTML)を拡張しますが、HDAの基本的なRESTfulアーキテクチャに取って代わったり妨害したりすることはありません。

この記事では、この最後のコメントを詳しく説明し、RESTfulなハイパーメディア主導のアプリケーションを「取って代わったり」「妨害したり」しないスクリプティングの仕組みについて説明します。これらの経験則は、Webアプリケーションを直接サポートするために書かれたスクリプティングだけでなく、汎用のJavaScriptライブラリにも適用されます。

ハイパーメディア対応スクリプティングの基本的なルールは次のとおりです。

以下に、これらの各ルールについて詳しく説明します。

#The Prime Directive

HDAのプライムディレクティブは、Hypermedia As The Engine of Application Stateを使用することです。ハイパーメディア対応スクリプティングアプローチはこのディレクティブに従います。

実際には、これにより、スクリプティングはサーバーとの間でハイパーメディア以外の交換をネットワーク上で行うことを回避する必要があります。

したがって、一般に、ハイパーメディア対応スクリプティングはfetch()XMLHttpRequestの使用を避ける必要があります。ただし、サーバーからの応答がデータAPI形式(例: プレーンJSON)ではなく、何らかのハイパーメディア(例: HTML)を使用する場合を除きます。

HATEOASを尊重するためには、一般的に、JavaScript(DOMではなく)に格納された複雑な状態を避ける必要があることも意味します。

ただし、この最後のステートメントには条件があります。ピュアHTMLよりも高度なフロントエンドエクスペリエンス(例: ウィジェット)を直接サポートする限り、状態はクライアント側にJavaScriptで格納できます。

RESTでのスクリプティングの目的に関してフィールディングが述べたことを繰り返すと

展開後に機能をダウンロードできるようにすると、システムの拡張性が向上します。

したがって、スクリプティングは追加の機能を基本的なハイパーメディアに直接実装せずに作成でき、ハイパーメディア(例: HTML)をより拡張可能にすることができるため、RESTfulシステムの正当な部分です。

その種の機能の良い例はリッチテキストエディタです。エディタのドキュメントの非常に高度な JavaScript モデルがあり、選択情報、強調情報の表示、コード補完などが含まれます。しかし、このモデルは DOM の残りの部分から分離され、リッチテキストエディタはその情報を標準のハイパーメディア機能を使用して DOM に公開する必要があります。たとえば、コンテンツを取得するための JavaScript API の呼び出しが必要になるのではなく、隠れた入力を利用して、エディタの内容を周囲の DOM に伝達する必要があります。

アイデアは、標準のハイパーメディア(HTML)ツールセットの一部ではない機能を提供することにより、スクリプティングを使用してハイパーメディア体験を向上させることです。ただし、多くの SPA フレームワークが実行しているように、HTML を大規模な JavaScript アプリケーション内の単なる UI 記述言語に格下げするのではなく、HTML と適切に連携する方法で行います。

#State

ただし、Hypermedia As The Engine Of Application State を使用しても、独自のクライアント側の状態を持つ ことはできないということではありません。明らかに、上で引用したリッチテキストエディタの例には、かなり量のクライアント側の状態がある可能性があります。ただし、クライアント側状態が正当で、ハイパーメディア主導アプリケーションと完全に一致する、より単純なケースがあります。

ボタンやアンカーをクリックすると另一个要素にクラスが追加され、それが見えるようになるシンプルな表示切り替えについて考えてみましょう。

この一時的なクライアント側の状態は、ハイパーメディア主導アプリケーションでは問題ありません。なぜなら、状態は純粋にフロントエンドだからです。この種のスクリプティングによってシステム状態は更新されません。システム状態が変更された場合(つまり、要素の表示または非表示がサーバーに保存されているデータに影響を与える場合)、ハイパーメディアの交換を使用する必要があります。

考慮すべき重要な側面は、クライアント側で更新された状態をサーバーと同期させる必要がるかどうかです。
必要な場合は、ハイパーメディアの交換を使用する必要があります。不要な場合は、状態をクライアント側だけに保持しても問題ありません。

#Events

JavaScript ライブラリがハイパーメディアフレンドリなスクリプティングを実現するための優れた方法の 1 つは、豊富なカスタムイベントモデルを持つことです。

イベントをトリガーする JavaScript ベースのコンポーネントを使用すると、htmx などのハイパーメディア指向の JavaScript ライブラリで、それらのイベントを監視してハイパーメディアの交換をトリガーできます。これにより、どの JavaScript ライブラリも、ユーザー選択のアクションを通じてハイパーメディア主導アプリケーションを駆動できる潜在的なハイパーメディア制御になります。

その良い例が Sortable.js の例で、htmx は Sortable.js によってトリガーされるend イベントを監視します

<form class="sortable" hx-post="/items" hx-trigger="end">
  <div class="htmx-indicator">Updating...</div>
  <div><input type='hidden' name='item' value='1'/>Item 1</div>
  <div><input type='hidden' name='item' value='2'/>Item 2</div>
  <div><input type='hidden' name='item' value='3'/>Item 3</div>
  <div><input type='hidden' name='item' value='4'/>Item 4</div>
  <div><input type='hidden' name='item' value='5'/>Item 5</div>
</form>

end イベントは、ドラッグアンドドロップが完了すると Sortable.js によってトリガーされます。htmx は hx-trigger 属性を介してこのイベントを監視し、HTTP リクエストを発行してハイパーメディアとサーバーを交換します。これにより、この Sortable.js ドラッグアンドドロップによるウィジェットは、新しく強力なハイパーメディア制御に変わります。

#Islands

Web 開発の最近のトレンドは、“isles” の概念です。

island アーキテクチャは、サーバー側にレンダリングされた Web ページ内の小さく焦点を合わせたインタラクティビティのチャンクを推奨します。

より高度なスクリプティングアプローチが必要であり、通常のハイパーメディア交換メカニズムの外側でサーバーと通信する必要がある場合、最もハイパーメディアフレンドリなアプローチは island アーキテクチャを使用することです。これにより、非ハイパーメディアコンポーネントはハイパーメディア主導アプリケーションの残りの部分から分離されます。

イベントは、ハイパーメディア主導ではない island をハイパーメディア主導アプリケーション内に統合するクリーンな方法であり、上で説明した Sortable.js の例の場合のように、「内部」 island を「外部」島に変換できます。

デニズ・アクシムシェクは、ハイパーメディア駆動アプリケーション内に非ハイパーメディアアイランドを埋め込む方が、その逆よりも通常は簡単であるという考察を行いました。

#インラインスクリプト

ハイパーメディアに優しいスクリプティングの最終的なルールはインラインスクリプティングです。スクリプトを外部ファイルに配置するのではなく、ハイパーメディア内に直接スクリプトを記述します。これは、ここでリストされている他のものと比較して物議を醸す概念であり、私たちはハイパーメディアに優しいスクリプティングのための「オプション」のルールであると考えています。考慮する価値はありますが、必須ではありません。

このスクリプティングのアプローチは特異ですが、いくつかのHTMLスクリプティングライブラリで採用されています。特にAlpine.jshyperscriptです。

インラインスクリプトを示すhyperscriptの例を次に示します。

<button _="on click toggle .visible on the next <section/>">
    Show Next Section
</button>
<section>
    ....
</section>

このボタンは、クリックするとsection要素の.visibleクラスを切り替えします。

ハイパーメディアスクリプティングに対するこのインラインアプローチの主な利点は、概念的にはハイパーメディア自体がハイパーメディアのスクリプティングよりも重視されるという点です。

ハイパーメディア/HTMLが組み込まれているスクリプティング言語(JavaScript)がコアコンセプトであるJSXコンポーネントを使用して、このコードとの対比を考えてみてください。

class Button extends React.Component {
    constructor(props) {
        // ...
    }
    toggleVisibilityOnNextSection() {
        // ...
    }
    render() {
        return <button onClick={this.toggleVisibilityOnNextSection}>{this.props.text}</button>;
    }
}

ここでは、ハイパーメディア/HTMLがUI記述メカニズムとして使用されているため、JavaScriptが主な使用技術であることがわかります。この場合、HTMLがハイパーメディアであるという事実はほとんど関係ありません。

とはいえ、インラインスクリプティングとJSXアプローチには共通の利点があります。どちらもLocality of Behavior(LoB)の設計原則を満たしています。どちらも挙動を問題の要素またはコンポーネントにローカライズするため、これらの要素とコンポーネントが何を実行しているのかをより簡単に確認できます。

もちろん、インラインスクリプトでは、ハイパーメディア内で直接実行されるスクリプティングの量にはソフトな制限があるはずです。ハイパーメディアをスクリプティングで圧倒してしまい、ハイパーメディアドキュメントの「形状」を理解するのが難しくなることは避けたいと考えています。

ライブラリ関数を呼び出したりhyperscript挙動を使用したりする手法を使用すると、インラインスクリプティングを使用しながら、実装を別個のファイルまたは場所に引き出すことができます。

インラインスクリプティングはスクリプティングがハイパーメディアに優しいためには必須ではありませんが、より従来のスクリプティング/ハイパーメディアの分離に対する代替案として検討する価値はあります。

#実用主義

もちろん、現実世界ではHATEOASに違反し、イベントをトリガーしない便利なJavaScriptライブラリが数多くあります。これにより、ハイパーメディア駆動アプリケーションに適合しにくくなることがよくあります。それにもかかわらず、これらのライブラリは、他の場所では見つけるのが難しい重要な機能を提供する場合があります。

このような場合、私たちは実用主義を提唱します。ライブラリをハイパーメディアフレンドリーに変更したり、ハイパーメディアフレンドリーな方法でラップしたりするのが簡単であれば、それは良い選択肢となるかもしれません。あなたが決して知らない、アップストリームの著者はプルリクエストを検討する可能性がありますライブラリの向上に役立ちます。

しかし、そうでなく、他に良い選択肢がない場合は、JavaScriptライブラリを設計どおりに使用してください。

ハイパーメディアに適さないライブラリをアプリケーションの他の部分から分離しようとしますが、一般的にはあまりにも多くの複雑さの予算を概念的な純粋性の維持に費やさないでください:十分な日を悪に。

</>