1. 序章

このチュートリアルでは、RESTFulAPIを使用してデータセットに簡単にアクセスできる標準プロトコルであるODataについて説明します。

2. OData とは何ですか?

ODataは、RESTfulAPIを使用してデータにアクセスするためのOASISおよびISO/IEC標準です。 そのため、消費者は標準のHTTP呼び出しを使用してデータセットを検出してナビゲートできます。

たとえば、簡単なカールワンライナーを使用して、公開されているODataサービスの1つにアクセスできます。

curl -s https://services.odata.org/V2/Northwind/Northwind.svc/Regions
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xml:base="https://services.odata.org/V2/Northwind/Northwind.svc/" 
  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
  xmlns="http://www.w3.org/2005/Atom">
    <title type="text">Regions</title>
    <id>https://services.odata.org/V2/Northwind/Northwind.svc/Regions</id>
... rest of xml response omitted

この記事の執筆時点では、ODataプロトコルは4番目のバージョンであり、より正確には4.01です。 OData V4は2014年にOASIS標準レベルに達しましたが、より長い歴史があります。 そのルーツは、2007年にがADO.NetDataServicesに名前が変更されたAstoriaと呼ばれるMicrosoftプロジェクトにまでさかのぼることができます。 このプロジェクトを発表する元のブログエントリは、MicrosoftのODataブログで引き続き利用できます。

データセットにアクセスするための標準ベースのプロトコルがあると、JDBCやODBCなどの標準APIに比べていくつかの利点があります。エンドユーザーレベルのコンシューマーとして、Excelなどの一般的なツールを使用して互換性のある任意のツールからデータを取得できますプロバイダー。 プログラミングは、利用可能な多数のRESTクライアントライブラリによっても容易になります。

プロバイダーとして、ODataを採用することには利点もあります。互換性のあるサービスを作成すると、エンドユーザーが選択したツールを使用して利用できる貴重なデータセットの提供に集中できます。 HTTPベースのプロトコルであるため、セキュリティメカニズム、監視、ロギングなどの側面も活用できます。

これらの特性により、ODataは、このディレクトリを確認することで確認できるため、公共データサービスを実装する際に政府機関によって人気のある選択肢になりました。

3. ODataの概念

ODataプロトコルの中核となるのは、エンティティデータモデル(略してEDM)の概念です。 EDMは、いくつかのメタエンティティを含むメタデータドキュメントを介してODataプロバイダーによって公開されたデータを記述します。

  • エンティティタイプとそのプロパティ(例: 個人顧客注文など)およびキー
  • エンティティ間の関係
  • エンティティに埋め込まれた構造化タイプを記述するために使用される複合タイプ(たとえば、 Customer タイプの一部であるアドレスタイプ)
  • 特定のタイプのエンティティを集約するエンティティセット

仕様では、このメタデータドキュメントは、サービスへのアクセスに使用されるルートURLの標準の場所 $metadataで利用可能である必要があります。 たとえば、 http://example.org/odata.svc/ で利用可能なODataサービスがある場合、そのメタデータドキュメントはhttp://example.org/odataで利用可能になります.svc / $metadata

返されるドキュメントには、このサーバーでサポートされているスキーマを説明する一連のXMLが含まれています。

<?xml version="1.0"?>
<edmx:Edmx 
  xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" 
  Version="1.0">
    <edmx:DataServices 
      xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
      m:DataServiceVersion="1.0">
    ... schema elements omitted
    </edmx:DataServices>
</edmx:Edmx>

このドキュメントをメインセクションに分解してみましょう。

トップレベルの要素、 子供は1人だけです。 エレメント 。 ここで重要なのは、サーバーが使用するODataバージョンを識別できる名前空間URIです。 この場合、名前空間は、Microsoftの識別子を使用するODataV2サーバーがあることを示しています。

DataServices 要素には、1つ以上の Schema 要素を含めることができ、それぞれが使用可能なデータセットを記述します。 Schema で使用可能な要素の完全な説明はこの記事の範囲を超えているため、最も重要な要素である EntityTypes、Associations、およびEntitySetsに焦点を当てます。

3.1. EntityType要素

この要素は、主キーを含む、特定のエンティティの使用可能なプロパティを定義します。 また、他のスキーマタイプとの関係に関する情報も含まれている場合があります。例を見ると、 CarMaker – は、他のORMテクノロジで見られる説明とそれほど変わらないことがわかります。 JPAとして:

<EntityType Name="CarMaker">
    <Key>
        <PropertyRef Name="Id"/>
    </Key>
    <Property Name="Id" Type="Edm.Int64" 
      Nullable="false"/>
    <Property Name="Name" Type="Edm.String" 
      Nullable="true" 
      MaxLength="255"/>
    <NavigationProperty Name="CarModelDetails" 
      Relationship="default.CarModel_CarMaker_Many_One0" 
      FromRole="CarMaker" 
      ToRole="CarModel"/>
</EntityType>

ここで、 CarMaker には、IdNameの2つのプロパティと、別のEntityTypeへの関連付けのみがあります。 Key s ub-elementは、エンティティの主キーをその Id プロパティとして定義し、各 Property 要素には、名前などのエンティティのプロパティに関するデータが含まれます。タイプまたはnull可能性。

NavigationProperty は、関連するエンティティへの「アクセスポイント」を記述する特別な種類のプロパティです。

3.2. 関連付け要素

Association 要素は、2つのエンティティ間の関連付けを記述します。これには、両端の多重度と、オプションで参照整合性制約が含まれます。

<Association Name="CarModel_CarMaker_Many_One0">
    <End Type="default.CarModel" Multiplicity="*" Role="CarModel"/>
    <End Type="default.CarMaker" Multiplicity="1" Role="CarMaker"/>
    <ReferentialConstraint>
        <Principal Role="CarMaker">
            <PropertyRef Name="Id"/>
        </Principal>
        <Dependent Role="CarModel">
            <PropertyRef Name="Maker"/>
        </Dependent>
    </ReferentialConstraint>
</Association>

ここで、 Association 要素は、CarModelエンティティとCarMakerエンティティ間の1対多の関係を定義し、前者は従属パーティとして機能します。

3.3. EntitySet要素

ここで説明する最後のスキーマの概念は、 EntitySet 要素です。これは、特定のタイプのエンティティのコレクションを表します。 それらをテーブルに類似していると考えるのは簡単ですが、多くの場合、それらはまさにそれですが、より良いアナロジーはビューのアナロジーです。 その理由は、同じEntityType に対して複数のEntitySet要素を使用でき、それぞれが使用可能なデータの異なるサブセットを表すためです。

トップレベルのスキーマ要素であるEntityContainer要素は、使用可能なすべてのEntitySetをグループ化します。

<EntityContainer Name="defaultContainer" 
  m:IsDefaultEntityContainer="true">
    <EntitySet Name="CarModels" 
      EntityType="default.CarModel"/>
    <EntitySet Name="CarMakers" 
      EntityType="default.CarMaker"/>
</EntityContainer>

簡単な例では、2つの EntitySet がありますが、ForeignCarMakersHistoricCarMakersなどのビューを追加することもできます。

4. ODataのURLとメソッド

ODataサービスによって公開されたデータにアクセスするために、通常のHTTP動詞を使用します。

  • GETは1つ以上のエンティティを返します
  • POSTは、既存のエンティティセットに新しいエンティティを追加します
  • PUTは特定のエンティティを置き換えます
  • PATCHは、特定のエンティティの特定のプロパティを置き換えます
  • DELETEは特定のエンティティを削除します

これらすべての操作には、アクションを実行するためのリソースパスが必要です。 リソースパスは、エンティティセット、エンティティ、またはエンティティ内のプロパティを定義する場合があります。

以前のODataサービスにアクセスするために使用されたURLの例を見てみましょう。

http://example.org/odata/CarMakers

このURLの最初の部分は、プロトコルから odata / パスセグメントまで、サービスルートURL と呼ばれ、このサービスのすべてのリソースパスで同じです。  サービスルートは常に同じであるため、次のURLサンプルでは省略記号(「…」)に置き換えます。

この場合、 CarMakers は、サービスメタデータで宣言されたEntitySetsの1つを参照します。 通常のブラウザを使用してこのURLにアクセスすると、このタイプの既存のすべてのエンティティを含むドキュメントが返されます。

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" 
  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
  xml:base="http://localhost:8080/odata/">
    <id>http://localhost:8080/odata/CarMakers</id>
    <title type="text">CarMakers</title>
    <updated>2019-04-06T17:51:33.588-03:00</updated>
    <author>
        <name/>
    </author>
    <link href="CarMakers" rel="self" title="CarMakers"/>
    <entry>
      <id>http://localhost:8080/odata/CarMakers(1L)</id>
      <title type="text">CarMakers</title>
      <updated>2019-04-06T17:51:33.589-03:00</updated>
      <category term="default.CarMaker" 
        scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
      <link href="CarMakers(1L)" rel="edit" title="CarMaker"/>
      <link href="CarMakers(1L)/CarModelDetails" 
        rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/CarModelDetails" 
        title="CarModelDetails" 
        type="application/atom+xml;type=feed"/>
        <content type="application/xml">
            <m:properties>
                <d:Id>1</d:Id>
                <d:Name>Special Motors</d:Name>
            </m:properties>
        </content>
    </entry>  
  ... other entries omitted
</feed>

返されるドキュメントには、CarMakerインスタンスごとにentry要素が含まれています。

私たちが利用できる情報を詳しく見てみましょう。

  • id :この特定のエンティティへのリンク
  • title / author / updated :このエントリに関するメタデータ
  • link 要素:エンティティの編集に使用されるリソース( rel =” edit” )または関連エンティティを指すために使用されるリンク。 この場合、この特定のCarMakerに関連付けられたCarModelエンティティのセットに移動するリンクがあります。
  • content CarModelエンティティのプロパティ値

ここで注意すべき重要な点は、エンティティセット内の特定のエンティティを識別するためのキーと値のペアの使用です。 この例では、キーは数値であるため、 CarMaker(1L)のようなリソースパスは、主キーの値が1に等しいエンティティを参照します。ここでの「L」は単に long 値であり、省略できます。

5. クエリオプション

返されるセットのサイズやその順序を制限するなど、返されるデータのさまざまな側面を変更するために、クエリオプションをリソースURLに渡すことができます。 OData仕様では豊富なオプションのセットが定義されていますが、ここでは最も一般的なオプションに焦点を当てます。

原則として、クエリオプションは相互に組み合わせることができるため、クライアントはページング、フィルタリング、結果リストの順序付けなどの一般的な機能を簡単に実装できます。

5.1. $topおよび$skip

$topと$skipのクエリオプションを使用して、大規模なデータセットをナビゲートできます。

.../CarMakers?$top=10&$skip=10

$ top は、CarMakersエンティティセットの最初の10レコードのみが必要であることをサービスに通知します。 $ skip、は、 $ top、の前に適用され、最初の10レコードをスキップするようにサーバーに指示します。

通常、特定のエンティティセットのサイズを知っておくと便利です。この目的のために、 $countサブリソースを使用できます。

.../CarMakers/$count

このリソースは、対応するセットのサイズを含む text /plainドキュメントを生成します。 ここでは、プロバイダーによってサポートされている特定のODataバージョンに注意を払う必要があります。 ODataV2はコレクションからのサブリソースとして$count をサポートしますが、V4ではクエリパラメーターとして使用できます。 この場合、 $ count はブール値であるため、それに応じてURLを変更する必要があります。

.../CarMakers?$count=true

5.2. $ filter

$ filter クエリオプションを使用して、で、指定されたエンティティセットから返されるエンティティを指定された条件に一致するエンティティに制限します。  $ filter の値は、基本的な演算子、グループ化、およびいくつかの便利な関数をサポートする論理式です。 たとえば、Name属性が文字「B」で始まるすべてのCarMakerインスタンスを返すクエリを作成しましょう。

.../CarMakers?$filter=startswith(Name,'B')

次に、いくつかの論理演算子を組み合わせて、特定のYearおよびMakerCarModelsを検索しましょう。

.../CarModels?$filter=Year eq 2008 and CarMakerDetails/Name eq 'BWM'

ここでは、等式演算子eqを使用してプロパティの値を指定しました。 また、式で関連エンティティのプロパティを使用する方法も確認できます。

5.3. $ expand

デフォルトでは、ODataクエリは関連するエンティティのデータを返しません。これは通常は問題ありません。 $ expand クエリオプションを使用して、特定の関連エンティティからのデータをメインコンテンツにインラインで含めるように要求できます。

サンプルドメインを使用して、特定のモデルとそのメーカーからのデータを返すURLを作成し、サーバーへの追加のラウンドトリップを回避しましょう。

.../CarModels(1L)?$expand=CarMakerDetails

返されるドキュメントには、関連エンティティの一部としてCarMakerデータが含まれるようになりました。

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" 
  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
  xml:base="http://localhost:8080/odata/">
    <id>http://example.org/odata/CarModels(1L)</id>
    <title type="text">CarModels</title>
    <updated>2019-04-07T11:33:38.467-03:00</updated>
    <category term="default.CarModel" 
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
    <link href="CarModels(1L)" rel="edit" title="CarModel"/>
    <link href="CarModels(1L)/CarMakerDetails" 
      rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/CarMakerDetails" 
      title="CarMakerDetails" 
      type="application/atom+xml;type=entry">
        <m:inline>
            <entry xml:base="http://localhost:8080/odata/">
                <id>http://example.org/odata/CarMakers(1L)</id>
                <title type="text">CarMakers</title>
                <updated>2019-04-07T11:33:38.492-03:00</updated>
                <category term="default.CarMaker" 
                  scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
                <link href="CarMakers(1L)" rel="edit" title="CarMaker"/>
                <link href="CarMakers(1L)/CarModelDetails" 
                  rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/CarModelDetails" 
                  title="CarModelDetails" 
                  type="application/atom+xml;type=feed"/>
                <content type="application/xml">
                    <m:properties>
                        <d:Id>1</d:Id>
                        <d:Name>Special Motors</d:Name>
                    </m:properties>
                </content>
            </entry>
        </m:inline>
    </link>
    <content type="application/xml">
        <m:properties>
            <d:Id>1</d:Id>
            <d:Maker>1</d:Maker>
            <d:Name>Muze</d:Name>
            <d:Sku>SM001</d:Sku>
            <d:Year>2018</d:Year>
        </m:properties>
    </content>
</entry>

5.4. $ select

$ selectクエリオプションを使用して、指定されたプロパティの値のみを返す必要があることをODataサービスに通知します。 これは、エンティティに多数のプロパティがあるシナリオで役立ちますが、関心があるのはそのうちのいくつかだけです。

NameおよびSkuプロパティのみを返すクエリでこのオプションを使用してみましょう。

.../CarModels(1L)?$select=Name,Sku

結果のドキュメントには、要求されたプロパティのみが含まれます。

... xml omitted
    <content type="application/xml">
        <m:properties>
            <d:Name>Muze</d:Name>
            <d:Sku>SM001</d:Sku>
        </m:properties>
    </content>
... xml omitted

また、関連するエンティティも省略されていることがわかります。 それらを含めるには、 $selectオプションにリレーションの名前を含める必要があります。

5.5. $ orderBy

$ orderBy オプションは、対応するSQLオプションとほとんど同じように機能します。 これを使用して、サーバーが特定のエンティティのセットを返す順序を指定します。より単純な形式では、その値は、選択したエンティティのプロパティ名のリストであり、オプションで順序を通知します。方向:

.../CarModels?$orderBy=Name asc,Sku desc

このクエリにより、 CarModels のリストが、名前とSKUの昇順、降順で表示されます。

ここで重要な詳細は、特定のプロパティの方向部分で使用されるケースです。仕様では、サーバーはキーワードascdescの大文字と小文字の任意の組み合わせをサポートする必要があります。 、またクライアントが小文字のみを使用することを義務付けています。

5.6. $ format

このオプションは、サーバーが使用する必要のあるデータ表現形式を定義します。これは、AcceptなどのHTTPコンテンツネゴシエーションヘッダーよりも優先されます。 その値は、完全なMIMEタイプまたはフォーマット固有の短い形式である必要があります。

たとえば、 application / json:の省略形としてjsonを使用できます。

.../CarModels?$format=json

このURLは、前に見たように、XMLではなくJSON形式を使用してデータを返すようにサービスに指示します。 このオプションが存在しない場合、サーバーは Acceptヘッダーの値を使用します(存在する場合)。 どちらも使用できない場合、サーバーは任意の表現(通常はXMLまたはJSON)を自由に選択できます。

特にJSONに関しては、基本的にスキーマレスです。 ただし、OData 4.01は、メタデータエンドポイントのJSONスキーマも定義しています。 これは、XML処理を選択した場合に、XML処理を完全に取り除くことができるクライアントを作成できることを意味します。

6. 結論

このODataの簡単な紹介では、その基本的なセマンティクスと、単純なデータセットナビゲーションを実行する方法について説明しました。 私たちのフォローアップ記事は、私たちが去ったところから続き、オリンゴ図書館に直行します。 次に、このライブラリを使用してサンプルサービスを実装する方法を説明します。

コード例は、いつものように、GitHubで入手できます。