コンテンツにスキップ

Web IDL

出典: フリー教科書『ウィキブックス(Wikibooks)』

Web IDLハンドブック

[編集]

1. イントロダクション

[編集]

Web IDLとは何か

[編集]

Web IDL(Web Interface Definition Language)は、ウェブプラットフォームのAPIを形式的に記述するための言語です。これは、ブラウザやその他のウェブ関連環境で実装されるインターフェースの仕様を定義するために使用されます。World Wide Web Consortium(W3C)によって標準化され、HTMLDOMWebGLWebRTCなど多くのウェブ標準で使用されています。

Web IDLの目的と重要性

[編集]

Web IDLの主な目的は、プラットフォームに依存しない方法でウェブAPIを記述することです。これにより、異なるブラウザベンダーが一貫した方法でAPIを実装できるようになります。また、JavaScriptC++Rustなど、複数のプログラミング言語にマッピングできる中間表現としても機能します。

Web IDLは以下のような利点を提供します:

  • APIの形式的な記述により、実装者が仕様を正確に理解できる
  • 異なるブラウザ間での一貫性の促進
  • 自動テストやドキュメント生成のための基盤の提供
  • APIの設計上の問題を早期に発見するための構造化された方法の提供

本ハンドブックの使い方

[編集]

本ハンドブックは、Web IDLの概念から始めて、徐々に高度なトピックへと進みます。各章にはコード例と実践的な説明が含まれており、必要に応じて表を使用して情報を整理しています。プログラマーとしての経験レベルに関わらず、ウェブAPIの設計や実装に携わる方々に役立つ内容となっています。

経験豊富な開発者であれば、必要な章に直接ジャンプして参照することもできます。初心者の方は、順を追って読み進めることをお勧めします。

2. Web IDL基礎

[編集]

構文の基本

[編集]

Web IDLは、C++Javaに似た宣言的な構文を持っています。基本的な構造は、インターフェース、辞書、列挙型などの型定義から成り立っています。

interface Node {
  readonly attribute DOMString nodeName;
  Node? parentNode();
  Node appendChild(Node newChild);
};

dictionary NodeInit {
  DOMString name = "";
  boolean readOnly = false;
};

enum NodeType {
  "element",
  "attribute",
  "text"
};

データ型と値

[編集]

Web IDLは豊富な型システムを持っており、JavaScript値と直接マッピングされます。

Web IDL型 JavaScript型 説明
boolean Boolean true または false
byte, octet, short, unsigned short, long, unsigned long, long long, unsigned long long Number 様々な範囲の整数値
float, unrestricted float, double, unrestricted double Number 浮動小数点値
DOMString String UTF-16文字列
USVString String UTF-16文字列(サロゲートペアの扱いが異なる)
ByteString String バイト文字列(ASCII範囲のみ)
sequence\<T> Array T型の要素を持つ配列
record\<K, V> Object キーがK型、値がV型のオブジェクト
Promise\<T> Promise T型で解決されるPromise
object Object 任意のオブジェクト
any 任意の型

インターフェースの概念

[編集]

インターフェースは、Web IDLの中心的な構造です。オブジェクトが提供するメソッドや属性を定義します。

interface Element : Node {
  readonly attribute DOMString tagName;
  DOMString getAttribute(DOMString name);
  void setAttribute(DOMString name, DOMString value);
  boolean hasAttribute(DOMString name);
  void removeAttribute(DOMString name);
};

上記の例では、ElementインターフェースがNodeインターフェースを継承し、追加の属性とメソッドを定義しています。

メンバー(メソッド、属性)の定義

[編集]

インターフェースは以下の種類のメンバーを持つことができます:

interface ExampleInterface {
  // 属性(読み取り専用)
  readonly attribute DOMString name;
  
  // 属性(読み書き可能)
  attribute unsigned long count;
  
  // メソッド
  void reset();
  boolean process(DOMString input);
  
  // 定数
  const unsigned short DEFAULT_SIZE = 16;
};

3. インターフェース定義

[編集]

インターフェースの宣言

[編集]

インターフェースは、interfaceキーワードに続けてインターフェース名、中括弧で囲まれたメンバー定義のブロックで構成されます。

interface AudioNode {
  void connect(AudioNode destination);
  void disconnect();
  readonly attribute AudioContext context;
  readonly attribute unsigned long numberOfInputs;
  readonly attribute unsigned long numberOfOutputs;
};

継承の仕組み

[編集]

インターフェースは別のインターフェースを継承することができます。継承は、インターフェース名の後にコロンと親インターフェース名を記述することで指定します。

interface AudioBufferSourceNode : AudioNode {
  attribute float playbackRate;
  void start(optional double when = 0);
  void stop(optional double when = 0);
};

この例では、AudioBufferSourceNodeAudioNodeから継承し、親から継承した機能に加えて、再生速度の設定や再生の開始/停止といった追加の機能を提供します。

部分インターフェース(partial interface)

[編集]

部分インターフェースを使用すると、既存のインターフェース定義を拡張できます。これは、複数の仕様にまたがるインターフェースや、段階的に機能を追加する場合に便利です。

// 元のインターフェース
interface Document {
  readonly attribute DOMString URL;
  Element createElement(DOMString localName);
};

// 部分インターフェースによる拡張
partial interface Document {
  readonly attribute Element? activeElement;
  boolean hasFocus();
};

コンストラクタ

[編集]

インターフェースにコンストラクタを定義するには、constructor修飾子を使用します。

[Constructor,
 Constructor(DOMString message),
 Constructor(DOMString message, DOMString fileName),
 Constructor(DOMString message, DOMString fileName, unsigned long lineNumber)]
interface Error {
  readonly attribute DOMString message;
  readonly attribute DOMString fileName;
  readonly attribute unsigned long lineNumber;
};

より新しい構文では、以下のように記述することもできます:

interface Error {
  constructor();
  constructor(DOMString message);
  constructor(DOMString message, DOMString fileName);
  constructor(DOMString message, DOMString fileName, unsigned long lineNumber);
  
  readonly attribute DOMString message;
  readonly attribute DOMString fileName;
  readonly attribute unsigned long lineNumber;
};

4. メンバー定義

[編集]

属性(Attributes)

[編集]

属性は、オブジェクトのプロパティを表します。デフォルトでは読み書き可能ですが、readonly修飾子を付けることで読み取り専用にできます。

interface HTMLImageElement : HTMLElement {
  attribute DOMString alt;
  attribute DOMString src;
  attribute unsigned long width;
  attribute unsigned long height;
  readonly attribute boolean complete;
};

操作(Operations)

[編集]

操作(メソッド)は、オブジェクトが実行できる機能を表します。

interface CanvasRenderingContext2D {
  // パスの描画
  void beginPath();
  void closePath();
  
  // 線の描画
  void moveTo(double x, double y);
  void lineTo(double x, double y);
  void arc(double x, double y, double radius, double startAngle, double endAngle, optional boolean anticlockwise = false);
  
  // 描画スタイル
  attribute DOMString fillStyle;
  attribute DOMString strokeStyle;
  
  // 描画操作
  void fill();
  void stroke();
};

定数(Constants)

[編集]

定数は、インターフェースに関連付けられた固定値を表します。

interface XMLHttpRequest {
  const unsigned short UNSENT = 0;
  const unsigned short OPENED = 1;
  const unsigned short HEADERS_RECEIVED = 2;
  const unsigned short LOADING = 3;
  const unsigned short DONE = 4;
  
  readonly attribute unsigned short readyState;
  // その他のメンバー
};

静的メンバー(Static members)

[編集]

静的メンバーは、インターフェースのインスタンスではなく、インターフェース自体に関連付けられたメンバーです。

interface Math {
  const double PI = 3.141592653589793;
  const double E = 2.718281828459045;
  
  static double abs(double x);
  static double sin(double x);
  static double cos(double x);
  static double max(double... values);
};

5. 型システム

[編集]

プリミティブ型

[編集]

Web IDLは多くのプリミティブ型をサポートしています。

interface PrimitiveExample {
  // 論理値
  attribute boolean enabled;
  
  // 整数型
  attribute byte smallInt;          // -128〜127
  attribute octet smallUnsigned;    // 0〜255
  attribute short mediumInt;        // -32768〜32767
  attribute unsigned short mediumUnsigned; // 0〜65535
  attribute long largeInt;          // -2^31〜2^31-1
  attribute unsigned long largeUnsigned;   // 0〜2^32-1
  attribute long long veryLargeInt; // -2^63〜2^63-1
  attribute unsigned long long veryLargeUnsigned; // 0〜2^64-1
  
  // 浮動小数点
  attribute float singlePrecision;
  attribute unrestricted float singlePrecisionWithNaNAndInfinity;
  attribute double doublePrecision;
  attribute unrestricted double doublePrecisionWithNaNAndInfinity;
  
  // 文字列
  attribute DOMString utf16String;
  attribute USVString normalizedUtf16String;
  attribute ByteString asciiString;
};

シーケンス型、レコード型

[編集]

シーケンスとレコードは、複合データ型を表現します。

interface CollectionExample {
  // 整数の配列
  attribute sequence<long> numberList;
  
  // 文字列のシーケンス
  attribute sequence<DOMString> stringList;
  
  // 入れ子になったシーケンス(2次元配列)
  attribute sequence<sequence<double>> matrix;
  
  // 文字列をキー、数値を値とするマップ
  attribute record<DOMString, double> measurements;
  
  // 文字列をキー、オブジェクトを値とするマップ
  attribute record<DOMString, object> properties;
};

Promise型

[編集]

非同期操作を表すために、Promise型が使用されます。

interface FileReader {
  Promise<ArrayBuffer> readAsArrayBuffer(Blob blob);
  Promise<DOMString> readAsText(Blob blob, optional DOMString encoding);
  Promise<void> abort();
};

共用体型(Union types)

[編集]

共用体型を使用すると、複数の型のいずれかを取ることができる値を表現できます。

interface UnionExample {
  // 文字列または数値を受け付ける
  void process(DOMString or double input);
  
  // 文字列、数値、またはブール値を返す
  (DOMString or double or boolean) getProperty(DOMString name);
  
  // 文字列の配列またはオブジェクトを属性として持つ
  attribute (sequence<DOMString> or object) data;
};

Nullable型

[編集]

型名の後に?を付けることで、その型またはnullを取ることができる型を表現できます。

interface NullableExample {
  // nullを許容する文字列
  attribute DOMString? optionalName;
  
  // nullを許容するノード
  attribute Node? parentNode;
  
  // nullを返す可能性のあるメソッド
  Element? getElementById(DOMString id);
};

辞書(Dictionaries)

[編集]

辞書は、名前付きのフィールドを持つ構造体のような型を定義します。

dictionary PositionOptions {
  boolean enableHighAccuracy = false;
  unsigned long timeout = 0xFFFFFFFF;
  unsigned long maximumAge = 0;
};

interface Geolocation {
  Promise<GeolocationPosition> getCurrentPosition(optional PositionOptions options = {});
  long watchPosition(PositionCallback callback, optional PositionOptions options = {});
};

6. 特殊な機能

[編集]

イテレーター(Iterators)

[編集]

イテレーターを実装するインターフェースを定義できます。

interface NodeList {
  getter Node? item(unsigned long index);
  readonly attribute unsigned long length;
  iterable<Node>;
};

上記の例では、NodeListはイテレーター機能を持ち、JavaScriptのfor...ofループで使用できます。

コールバック関数

[編集]

コールバック関数は、callbackキーワードを使用して定義します。

callback EventListener = void (Event event);

interface EventTarget {
  void addEventListener(DOMString type, EventListener? callback);
  void removeEventListener(DOMString type, EventListener? callback);
  boolean dispatchEvent(Event event);
};

関数の代わりにインターフェースを実装するオブジェクトをコールバックとして使用する場合は、callback interfaceを使用します。

callback interface PermissionObserver {
  void permissionChanged(PermissionStatus status);
};

interface PermissionStatus {
  readonly attribute PermissionState state;
  attribute PermissionObserver? onchange;
};

例外処理

[編集]

Web IDLでは、操作が失敗した場合にスローされる例外を定義できます。

interface FileReader {
  // FileNotFoundExceptionをスローする可能性がある
  [Throws=FileNotFoundException]
  ArrayBuffer readAsArrayBuffer(DOMString filePath);
  
  // SecurityExceptionをスローする可能性がある
  [Throws=SecurityException]
  void readSecureData();
};

最新のWeb IDL仕様では、[Throws]構文を変更し、メソッドの戻り値にPromiseを使用して例外を処理することが推奨されています。

interface FileReader {
  Promise<ArrayBuffer> readAsArrayBuffer(DOMString filePath);
  Promise<void> readSecureData();
};

Mixin

[編集]

Mixinは、複数のインターフェースに共通のメンバーを定義するための仕組みです。

interface mixin WindowOrWorkerGlobalScope {
  void setTimeout(VoidFunction handler, optional long timeout = 0);
  void clearTimeout(long id);
  void setInterval(VoidFunction handler, optional long timeout = 0);
  void clearInterval(long id);
};

Window includes WindowOrWorkerGlobalScope;
WorkerGlobalScope includes WindowOrWorkerGlobalScope;

この例では、setTimeoutclearTimeoutなどのメソッドをWindowWorkerGlobalScopeの両方に提供しています。

7. 拡張と属性

[編集]

拡張属性(Extended attributes)の概要

[編集]

拡張属性は、Web IDL定義に追加のメタデータやセマンティクスを提供します。これらは角括弧内に記述され、様々なレベル(インターフェース、操作、属性など)に適用できます。

[Exposed=Window]
interface HTMLCanvasElement : HTMLElement {
  [HTMLConstructor] constructor();
  
  [CEReactions] attribute unsigned long width;
  [CEReactions] attribute unsigned long height;
  
  [NewObject] CanvasRenderingContext2D? getContext(DOMString contextId);
};

主要な拡張属性の解説

[編集]

以下は、頻繁に使用される拡張属性の解説です。

拡張属性 説明
Exposed インターフェースが公開されるグローバルスコープを指定 [Exposed=Window] または [Exposed=(Window,Worker)]
Global グローバルオブジェクトであることを示す [Global=Window] interface Window { ... };
Constructor インターフェースが直接構築可能であることを示す [Constructor] interface CustomEvent { ... };
HTMLConstructor HTML要素の標準的な構築を提供 [HTMLConstructor] interface HTMLElement { ... };
SecureContext セキュアコンテキスト(HTTPS)でのみ使用可能 [SecureContext] interface PaymentRequest { ... };
Unforgeable 属性が上書きできないことを示す [Unforgeable] readonly attribute DOMString origin;
SameObject 常に同じオブジェクトが返されることを示す [SameObject] readonly attribute Console console;
LegacyNullToEmptyString nullが空文字列に変換されることを示す [LegacyNullToEmptyString] attribute DOMString alt;

カスタム拡張属性の作成

[編集]

ブラウザベンダーや実装者は、特定の目的のためにカスタム拡張属性を定義することがあります。これらは通常、特定のプレフィックスを持ちます。

// Chromium固有の拡張属性
[RuntimeEnabled=ExperimentalFeature]
interface ExperimentalAPI {
  void doExperimentalThing();
};

// Firefoxの拡張属性の例
[ChromeOnly]
partial interface Navigator {
  readonly attribute MozGamepad gamepad;
};

8. 実装パターン

[編集]

ブラウザAPIでの実装例

[編集]

ブラウザAPIでは、よく使われるパターンがいくつかあります。以下にDOM APIの例を示します。

[Exposed=Window]
interface Document : Node {
  [SameObject] readonly attribute DOMImplementation implementation;
  readonly attribute DOMString URL;
  readonly attribute DOMString documentURI;
  readonly attribute DOMString compatMode;
  readonly attribute DOMString characterSet;
  readonly attribute DOMString charset;
  readonly attribute DOMString inputEncoding;
  readonly attribute DOMString contentType;
  
  [SameObject] readonly attribute DocumentType? doctype;
  [SameObject] readonly attribute Element? documentElement;
  
  HTMLCollection getElementsByTagName(DOMString qualifiedName);
  HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
  HTMLCollection getElementsByClassName(DOMString classNames);
  
  [CEReactions, NewObject] Element createElement(DOMString localName);
  [CEReactions, NewObject] Element createElementNS(DOMString? namespace, DOMString qualifiedName);
  [NewObject] DocumentFragment createDocumentFragment();
  [NewObject] Text createTextNode(DOMString data);
  [NewObject] Comment createComment(DOMString data);
  
  [CEReactions] Node importNode(Node node, optional boolean deep = false);
  [CEReactions] Node adoptNode(Node node);
  
  [SameObject] readonly attribute Location? location;
  
  // イベント関連
  attribute EventHandler onreadystatechange;
};

よくあるパターンと設計

[編集]

Web IDLでよく使われるパターンを以下に示します。

Factoryパターン:

interface DocumentBuilder {
  [NewObject] Document createDocument(optional DOMString type = "text/html");
  [NewObject] XMLDocument createXMLDocument(DOMString namespaceURI, DOMString qualifiedName);
};

イベント処理パターン:

interface EventTarget {
  void addEventListener(DOMString type, EventListener? callback, optional boolean useCapture = false);
  void removeEventListener(DOMString type, EventListener? callback, optional boolean useCapture = false);
  boolean dispatchEvent(Event event);
};

// イベントハンドラプロパティパターン
partial interface GlobalEventHandlers {
  attribute EventHandler onclick;
  attribute EventHandler onmousemove;
  attribute EventHandler onkeydown;
  // 他のイベントハンドラ
};

Named Constructorパターン:

[Exposed=Window,
 LegacyFactoryFunction=Image(optional unsigned long width, optional unsigned long height)]
interface HTMLImageElement : HTMLElement {
  // ...
};

ベストプラクティス

[編集]

Web IDLを使用する際のベストプラクティスを紹介します。

一貫性のある命名規則:

// 良い例:一貫した命名規則
interface AudioContext {
  AudioBuffer createBuffer(unsigned long numberOfChannels, unsigned long length, float sampleRate);
  AudioBufferSourceNode createBufferSource();
};

// 避けるべき例:一貫性のない命名
interface BadAudioContext {
  AudioBuffer makeBuffer(unsigned long channels, unsigned long size, float rate);
  AudioBufferSourceNode newBufferSource();
};

適切な型の使用:

// 良い例:適切な型の使用
interface GoodAPI {
  void setVolume(float level); // 0.0〜1.0の範囲
  void setPosition(double x, double y, double z);
  void setName(DOMString name);
};

// 避けるべき例:あいまいな型の使用
interface BadAPI {
  void setVolume(any level); // 型が不明確
  void setPosition(any x, any y, any z);
  void setName(any name);
};

適切なデフォルト値とオプションパラメータ:

// 良い例:明示的なデフォルト値を持つオプションパラメータ
interface FetchAPI {
  Promise<Response> fetch(USVString url, optional RequestInit options = {});
};

dictionary RequestInit {
  DOMString method = "GET";
  Headers headers;
  BodyInit? body = null;
  DOMString mode = "cors";
  DOMString credentials = "same-origin";
  DOMString cache = "default";
  DOMString redirect = "follow";
  DOMString referrer = "client";
  DOMString integrity = "";
};

9. ツールとリソース

[編集]

Web IDL解析ツール

[編集]

Web IDL定義を解析・処理するためのツールとして、以下のようなものがあります。

ツール名 プログラミング言語 説明
webidl2 JavaScript W3Cの標準的なWeb IDLパーサー
widlproc C Web IDLからドキュメントを生成するプロセッサ
WebIDL.js JavaScript Web IDLをJavaScriptに変換するツール
widl-nan C++/JavaScript Web IDL定義からNode.js向けのネイティブアドオンを生成

検証ツール

[編集]

Web IDL定義を検証するツールとして、以下のようなものがあります。

ツール名 用途
web-platform-tests WebIDL Web IDL定義の構文検証
Chromium's WebIDL Blink parser Blink実装用のWeb IDL解析・検証
Mozilla's WebIDL Parser Gecko実装用のWeb IDL解析・検証

コード生成ツール

[編集]

Web IDL定義から実装コードを生成するツールとして、以下のようなものがあります。

ツール名 出力言語 説明
PyWebIDL Python Web IDLからPythonバインディングを生成
rust-webidl Rust Web IDLからRustバインディングを生成
jWebIDL Java Web IDLからJavaバインディングを生成
webidl-to-ts TypeScript Web IDLからTypeScript型定義を生成

参考文献と仕様書

[編集]

Web IDLに関連する主要な仕様書とリソースは以下の通りです。

仕様書/リソース 説明
W3C Web IDL仕様 Web IDLの公式仕様
WHATWG Web IDL Living Standard 最新のWeb IDL標準
MDN Web API リファレンス Web IDLで定義されたAPIの使用方法
W3C/WHATWG標準 HTML、DOM、Fetchなど、Web IDLを使用して定義された標準

10. 付録

[編集]

Web IDL文法の完全リファレンス

[編集]

Web IDLの主要な文法構造を以下に示します。

// インターフェース定義
interface InterfaceName [: ParentInterface] {
  // メンバー定義
};

// 部分インターフェース
partial interface InterfaceName {
  // 追加メンバー
};

// 辞書定義
dictionary DictionaryName [: ParentDictionary] {
  // メンバー定義
};

// 部分辞書
partial dictionary DictionaryName {
  // 追加メンバー
};

// 列挙型
enum EnumName {
  // 列挙値
};

// コールバック
callback CallbackName = ReturnType (Parameters);

// コールバックインターフェース
callback interface CallbackInterfaceName {
  // メンバー定義
};

// Mixin定義
interface mixin MixinName {
  // メンバー定義
};

// Mixinのインクルード
InterfaceName includes MixinName;

用語集

[編集]
用語 定義
インターフェース APIで公開されるオブジェクトの形状を定義する構造
属性 オブジェクトのプロパティを定義するメンバー
操作 オブジェクトのメソッドを定義するメンバー
辞書 名前付きのフィールドを持つデータ構造
列挙型 固定セットの文字列値を定義する型
コールバック 関数型を定義する構造
Mixin 複数のインターフェースに共通のメンバーを定義する構造
拡張属性 Web IDL定義に追加情報を提供する修飾子
イテレーター 要素の列挙をサポートするインターフェース
Nullable null値を許容する型修飾子
Union型 複数の型のいずれかを取ることができる型