As developer, you probably have to work with APIs. Either you consume them, or perhaps you build them. Most of the time an API provides some sort of JSON response or perhaps XML. When the implementation is complete, it provides documentation as well, using the OpenAPI specification. This however is not what this blog is about.

The goal is to get you started exploring OData. OData is an OASIS Standard that defines the best practice for creating and using RESTful APIs. So in short, it is a web-based protocol for querying and updating data.

Meeting OData

OData (Open Data Protocol) was initiated by Microsoft in 2007, but my real first encounter was only since last year when I needed to get information out of a SAP system. The front-end developers use SAPUI5 that is based on OpenUI5. SAP made OData the standard for all solutions being developed using SAPUI5.

Why should I use it?

As more and more APIs are developed, the different ways how companies implement REST or SOAP services for consuming data grow as well. Some companies even created their own query language; for example SOQL from Salesforce. This makes it hard for development teams to connect and code against them. OData provides a standard way of implementing RESTful APIs that allow SQL-like querying to interact with them. It basically can be seen as SQL for the web, built on top of the standard protocols (HTTP, JSON). Now these days it’s widely adopted by a lot of companies, like Salesforce, MySQL, Microsoft, Oracle, IBM, Intel, Citrix, SAP…​ The list goes on. By using OData, you no longer need to talk about HTTP methods, URL conventions and query options. This is all provided by the OData protocol.

Is it safe?

You read SQL, but you probably are thinking "What about SQL Injection"? Using OData, it is indeed possible to query anything that is exposed by the model, just like SQL does on a table. If you want to secure certain parts, your program will have to provide for this security. OData is exposed as a REST API, so one should implement the same security measurements as for any other REST API, like securing against the OWASP top 10.

Breaking it down

Like any REST implementation, OData has a server and a client part. The server contains the OData Data Model. Any operation like $expand, $filter, $order, $top is handled by the server. The client only knows the data it got after a (requested) query. Another important part of the model is the metadata: it describes the abstract data model of the resources it exposes.

Metadata

At the core of the protocol is the concept of the Entity Data Model (EDM). It describes the exposed data through a metadata document. The $metadata is an EDMX (Entity Data Model XML) document that contains a complete description of the Entity types, properties etc. exposed by the service in EDM.

Listing 1. Example of entitytype desciption from the $metadata
<EntityType Name="Person">
  <Key>
    <PropertyRef Name="Id"/>
  </Key>
  <Property Name="Id" Type="Edm.Int32" Nullable="false"/>
  <Property Name="Name" Type="Edm.String" MaxLength="40"/>
  <Property Name="Surname" Type="Edm.String" MaxLength="40"/>
  <Property Name="Email" Type="Edm.String" MaxLength="241"/>
</EntityType>

OData URLs

In order to get the data from a given OData service, we use regular HTTP verbs, like GET, POST, DELETE. As in the example above, the URL to get the entity 'Person', the URL would look like: http://localhost:8080/odataservice/Person. To get a specific person based on the id, you just have to provide it: http://localhost:8080/odataservice/Person(123)

Queries

Now here comes another strength of OData: having an OData service, you can refine your query to get specific data.

$filter

Let’s say I want to filter on all persons with a given Surname, that would be easy as:

http://localhost:8080/odataservice/Person?$filter=Surname eq 'Jansen'

In your browser it would probably look like:

http://localhost:8080/odataservice/Person?$filter=Surname%20eq%20%27Jansen%27

Therefore, I find it more easy to use a tool like Postman to help me out. It’s even possible to filter on properties of joined entities (assuming the Person has a relation to the entity Address:

…​/odataservice/Person?$expand=Address($select=Street,Number)&$filter=Address/Street eq 'Streetname'&$format=json

This would then get all persons of a given street.

$expand

As seen in our previous query, I added $expand=Address to the query to get the related entity with the Person. Extending that with $select, it’s possible to only retrieve the Street and Number of that entity. The resulting data could then look like this:

{
  "@odata.context": "$metadata#Person(Address(Street,Number))",
  "value": [
    {
      "Id": 12345,
      "Name": "Foo",
      "Surname": "Bar",
      "Email": "foo.bar@company.org",
      "Address": {
        "Street": "Streetname",
        "Number": "14"
      }
    },
    {
      "Id": 12312,
      //....
    }
  ]
}

As you can see, there are a lot of possibilities, not even mentioning options like $top, $skip, $orderBy and $format. If you want to play around: there is a full working demo service available on services.odata.org. Here is just one example query to get you started. Want some practice? visit the online query tool to help you get started creating OData queries.

shadow-left