Panduan Protokol OData

1. Pengenalan

Dalam tutorial ini, kita akan meneroka OData, protokol standard yang membolehkan akses mudah ke set data menggunakan RESTFul API.

2. Apakah OData itu ?

OData adalah OASIS dan ISO / IEC Standard untuk mengakses data menggunakan RESTful API. Oleh itu, pengguna dapat menemui dan menavigasi melalui set data menggunakan panggilan HTTP standard.

Sebagai contoh, kita boleh mengakses salah satu perkhidmatan OData yang tersedia untuk umum dengan satu-liner curl sederhana :

curl -s //services.odata.org/V2/Northwind/Northwind.svc/Regions   Regions //services.odata.org/V2/Northwind/Northwind.svc/Regions ... rest of xml response omitted

Pada penulisan ini, protokol OData berada pada versi ke-4 - 4.01 untuk lebih tepat. OData V4 mencapai tahap standard OASIS pada tahun 2014, tetapi ia mempunyai sejarah yang lebih panjang. Kita dapat menelusuri akarnya ke projek Microsoft bernama Astoria, yang dinamakan semula menjadi ADO.Net Data Services pada tahun 2007. Entri blog asal yang mengumumkan projek ini masih boleh didapati di blog Microsoft OData.

Memiliki protokol berasaskan standard untuk mengakses set data membawa beberapa kelebihan berbanding API standard seperti JDBC atau ODBC. Sebagai pengguna tahap pengguna akhir, kita dapat menggunakan alat popular seperti Excel untuk mengambil data dari mana-mana pembekal yang serasi. Pengaturcaraan juga difasilitasi oleh sebilangan besar perpustakaan pelanggan REST yang tersedia.

Sebagai penyedia, penggunaan OData juga mempunyai faedah: setelah kami membuat perkhidmatan yang serasi, kami dapat memberi tumpuan pada penyediaan kumpulan data yang berharga, yang dapat digunakan oleh pengguna akhir menggunakan alat pilihan mereka. Oleh kerana itu adalah protokol berasaskan HTTP, kami juga dapat memanfaatkan aspek seperti mekanisme keselamatan, pemantauan, dan pembalakan.

Ciri-ciri itu menjadikan OData sebagai pilihan popular oleh agensi kerajaan ketika melaksanakan perkhidmatan data awam, kerana kami dapat memeriksa dengan melihat direktori ini.

3. Konsep OData

Inti protokol OData adalah konsep Model Data Entiti - atau EDM secara ringkas. EDM menerangkan data yang didedahkan oleh penyedia OData melalui dokumen metadata yang mengandungi sejumlah meta-entiti:

  • Jenis entiti dan sifatnya (seperti Orang , Pelanggan , Pesanan , dll) dan kunci
  • Hubungan antara entiti
  • Jenis kompleks yang digunakan untuk menggambarkan jenis berstruktur yang disatukan ke dalam entiti (katakanlah, jenis alamat yang merupakan sebahagian daripada jenis Pelanggan )
  • Set Entiti, yang menggabungkan entiti dari jenis tertentu

Spesifikasi mewajibkan bahawa dokumen metadata ini mesti tersedia di lokasi standard $ metadata pada URL root yang digunakan untuk mengakses perkhidmatan. Sebagai contoh, jika kita mempunyai perkhidmatan OData yang tersedia di //example.org/odata.svc/ , maka dokumen metadata-nya akan tersedia di //example.org/odata.svc/$metadata .

Dokumen yang dikembalikan mengandungi sekumpulan XML yang menggambarkan skema yang disokong oleh pelayan ini:

   ... schema elements omitted  

Mari kita hancurkan dokumen ini ke bahagian utamanya.

Elemen peringkat teratas, hanya boleh mempunyai satu anak, yang unsur .Perkara penting yang perlu diperhatikan di sini ialah URI ruang nama kerana ia membolehkan kita mengenal pasti versi OData mana yang digunakan pelayan. Dalam kes ini, ruang nama menunjukkan bahawa kita mempunyai pelayan OData V2, yang menggunakan pengecam Microsoft.

A DataServices unsur boleh mempunyai satu atau lebih Schema elemen, setiap menceritakan tentang sebuah set data boleh didapati. Oleh kerana penerangan lengkap mengenai elemen yang ada dalam Skema berada di luar ruang lingkup artikel ini, kami akan memberi tumpuan kepada yang paling penting: Jenis Entiti, Persatuan, dan Set Entiti .

3.1. Elemen Jenis Entiti

Elemen ini menentukan sifat yang ada pada entiti tertentu, termasuk kunci utamanya. Ini mungkin juga mengandungi maklumat mengenai hubungan dengan jenis skema lain dan, dengan melihat contoh - Pembuat Kereta - kita akan dapat melihat bahawa ia tidak jauh berbeza dengan penerangan yang terdapat dalam teknologi ORM lain, seperti JPA:

Di sini, Pembuat Kereta kami hanya mempunyai dua sifat - Id dan Nama - dan hubungan dengan Jenis Entiti yang lain . The Key s ub-unsur mentakrifkan kunci utama entiti adalah untuk menjadi Id harta, dan setiap Hartanah elemen mengandungi data mengenai harta entiti seperti nama, jenis atau nullability.

A NavigationProperty adalah sejenis khas harta yang menerangkan "pusat akses" kepada entiti yang berkaitan.

3.2. Elemen Persatuan

An Persatuan unsur menerangkan kaitan antara dua entiti, termasuk kepelbagaian pada setiap hujung dan secara pilihan integriti kekangan rujukan:

Di sini, Persatuan elemen mentakrifkan perhubungan satu ke banyak antara CarModel dan pembuat kereta entiti, di mana bekas bertindak sebagai parti bersandar.

3.3. Elemen EntitySet

Konsep skema terakhir yang akan kita terokai adalah elemen EntitySet , yang mewakili kumpulan entiti dari jenis tertentu. Walaupun mudah untuk menganggapnya serupa dengan jadual - dan dalam banyak kes, hanya itu - analogi yang lebih baik adalah pandangan. Sebabnya ialah kita boleh mempunyai banyak elemen EntitySet untuk EntityType yang sama , masing-masing mewakili subset data yang tersedia.

The EntityContainer elemen, yang merupakan unsur skema peringkat tertinggi, kumpulan semua EntitySet s:

Dalam contoh ringkas kami, kami hanya mempunyai dua EntitySet , tetapi kami juga dapat menambahkan pandangan tambahan, seperti ForeignCarMakers atau HistoricCarMakers .

4. URL dan Kaedah OData

Untuk mengakses data yang didedahkan oleh perkhidmatan OData, kami menggunakan kata kerja HTTP biasa:

  • GET mengembalikan satu atau lebih entiti
  • POST menambah entiti baru ke Set Entiti yang ada
  • PUT menggantikan entiti tertentu
  • PATCH menggantikan sifat tertentu entiti tertentu
  • DELETE membuang entiti tertentu

Semua operasi tersebut memerlukan jalan sumber untuk ditindaklanjuti. Laluan sumber boleh menentukan kumpulan entiti, entiti atau bahkan harta dalam entiti.

Let's take a look on an example URL used to access our previous OData service:

//example.org/odata/CarMakers 

The first part of this URL, starting with the protocol up to the odata/ path segment, is known as the service root URL and is the same for all resource paths of this service. Since the service root is always the same, we'll replace it in the following URL samples by an ellipsis (“…”).

CarMakers, in this case, refers to one of the declared EntitySets in the service metadata. We can use a regular browser to access this URL, which should then return a document containing all existing entities of this type:

  //localhost:8080/odata/CarMakers CarMakers 2019-04-06T17:51:33.588-03:00      //localhost:8080/odata/CarMakers(1L) CarMakers 2019-04-06T17:51:33.589-03:00      1 Special Motors    ... other entries omitted 

The returned document contains an entry element for each CarMaker instance.

Let's take a closer look at what information we have available to us:

  • id: a link to this specific entity
  • title/author/updated: metadata about this entry
  • link elements: Links used to point to a resource used to edit the entity (rel=”edit”) or to related entities. In this case, we have a link that takes us to the set of CarModel entities associated with this particular CarMaker.
  • content: property values of CarModel entity

An important point to notice here is the use of the key-value pair to identify a particular entity within an entity set. In our example, the key is numeric so a resource path like CarMaker(1L) refers to the entity with a primary key value equal to 1 – the “L” here just denotes a long value and could be omitted.

5. Query Options

We can pass query options to a resource URL in order to modify a number of aspects of the returned data, such as to limit the size of the returned set or its ordering. The OData spec defines a rich set of options, but here we'll focus on the most common ones.

As a general rule, query options can be combined with each other, thus allowing clients to easily implement common functionalities such as paging, filtering and ordering result lists.

5.1. $top and $skip

We can navigate through a large dataset using the $top an $skip query options:

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

$top tells the service that we want only the first 10 records of the CarMakers entity set. A $skip, which is applied before the $top, tells the server to skip the first 10 records.

It's usually useful to know the size of a given Entity Set and, for this purpose, we can use the $count sub-resource:

.../CarMakers/$count 

This resource produces a text/plain document containing the size of the corresponding set. Here, we must pay attention to the specific OData version supported by a provider. While OData V2 supports $count as a sub-resource from a collection, V4 allows it to be used as a query parameter. In this case, $count is a Boolean, so we need to change the URL accordingly:

.../CarMakers?$count=true 

5.2. $filter

We use the $filter query option to limit the returned entities from a given Entity Set to those matching given criteria. The value for the $filter is a logical expression that supports basic operators, grouping and a number of useful functions. For instance, let's build a query that returns all CarMaker instances where its Name attribute starts with the letter ‘B':

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

Now, let's combine a few logical operators to search for CarModels of a particular Year and Maker:

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

Here, we've used the equality operator eq to specify values for the properties. We can also see how to use properties from a related entity in the expression.

5.3. $expand

By default, an OData query does not return data for related entities, which is usually OK. We can use the $expand query option to request that data from a given related entity be included inline with the main content.

Using our sample domain, let's build an URL that returns data from a given model and its maker, thus avoiding an additional round-trip to the server:

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

The returned document now includes the CarMaker data as part of the related entity:

  //example.org/odata/CarModels(1L) CarModels 2019-04-07T11:33:38.467-03:00      //example.org/odata/CarMakers(1L) CarMakers 2019-04-07T11:33:38.492-03:00      1 Special Motors        1 1 Muze SM001 2018   

5.4. $select

We use the $select query option to inform the OData service that it should only return the values for the given properties. This is useful in scenarios where our entities have a large number of properties, but we're only interested in some of them.

Let's use this option in a query that returns only the Name and Sku properties:

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

The resulting document now has only the requested properties:

... xml omitted   Muze SM001   ... xml omitted

We can also see that even related entities were omitted. In order to include them, we'd need to include the name of the relation in the $select option.

5.5. $orderBy

The $orderBy option works pretty much as its SQL counterpart. We use it to specify the order in which we want the server to return a given set of entities. In its simpler form, its value is just a list of property names from the selected entity, optionally informing the order direction:

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

This query will result in a list of CarModels ordered by their names and SKUs, in ascending and descending directions, respectively.

An important detail here is the case used with the direction part of a given property: while the spec mandates that server must support any combination of upper- and lower-case letters for the keywords asc and desc, it also mandates that client use only lowercase.

5.6. $format

This option defines the data representation format that the server should use, which takes precedence over any HTTP content-negotiation header, such as Accept. Its value must be a full MIME-Type or a format-specific short form.

For instance, we can use json as an abbreviation for application/json:

.../CarModels?$format=json 

This URL instructs our service to return data using JSON format, instead of XML, as we've seen before. When this option is not present, the server will use the value of the Accept header, if present. When neither is available, the server is free to choose any representation – usually XML or JSON.

Mengenai JSON secara khusus, pada dasarnya ia adalah skema. Walau bagaimanapun, OData 4.01 mendefinisikan skema JSON untuk titik akhir metadata juga. Ini bermaksud bahawa kita sekarang dapat menulis klien yang dapat menyingkirkan pemprosesan XML jika mereka memilih untuk melakukannya.

6. Kesimpulannya

Dalam pengenalan ringkas mengenai OData ini, kami telah membahas semantik asasnya dan bagaimana melakukan navigasi set data yang mudah. Artikel susulan kami akan diteruskan di mana kami pergi dan terus masuk ke perpustakaan Olingo. Kami kemudian akan melihat bagaimana melaksanakan perkhidmatan sampel menggunakan perpustakaan ini.

Contoh kod, seperti biasa, terdapat di GitHub.