SAPUI5 (25) - Understanding OData and OpenUI5's OData Model

Keywords: Attribute JSON REST xml

This article introduces several important concepts, followed by the implementation of CRUD based on OData Model.

  • REST

The term REST(Representational State Transfer) was proposed by Roy Thomas Fielding in his doctoral dissertation in 2000 and translated into Chinese to denote the transmission of state at the presentation level. Because he was the main designer of HTTP protocol (version 1.0 and 1.1), one of the authors of Apache server software, and the first chairman of Apache Foundation, REST principles quickly became popular. When a software architecture conforms to REST principles, we call it RESTful architecture.

  • oData

Open Data Protocol (OData) is an OASIS standard that describes how to create and access Restful services. This standard was initiated by Microsoft. The first three versions 1.0, 2.0 and 3.0 are Microsoft Open Standards. The fourth version 4.0 was voted to become an open industrial standard in OASIS on March 17, 2014.

OData is a Web protocol for querying and updating data, providing a way to expose data that exists in applications. OData uses and builds on many Web technologies, such as HTTP, Atom Publishing Protocol (AtomPub) and JSON, to provide access to information from various applications, services and repositories. OData is used to expose and access information from various data sources, including, but not limited to, relational databases, file systems, content management systems and traditional Web sites.

As mentioned earlier, Rest is just an idea for designing Web services, not a standardized protocol. It is the lack of standardization that leads to the lack of uniformity and universality of Restful API s published by various countries. OData is a standard protocol proposed to remedy this deficiency.

View Northwind OData

http://services.odata.org/ This website provides an example of OData data and CRUD operations on OData data. Let's first look at these data to understand the knowledge points of OData.

Let's type in the browser first. http://services.odata.org/V3/(S(i2ebiza3pghgcecz3upusotg))/OData/OData.svc/ The site provides northwind sample data in xml format. This is a sample database commonly used by Microsoft, including the Access database under Office. To facilitate data viewing, it is recommended to use the Chrome plug-in: Postman. Chrome is ugly in looking at xml and json data formats. Or use IE browser. The following is the view effect of Postman:

Display data in json format

By default, it will be displayed in xml format, and by adding? $format=json after URI, it will be displayed in json format, such as: http://services.odata.org/V3/(S(i2ebiza3pghgcecz3upusotg))/OData/OData.svc/?$format=json It is displayed in json format.

Metadata

Add $metadata after the URI to display the metadata:

Request:
- type: GET
- uri: http://services.odata.org/V3/(S(i2ebiza3pghgcecz3upusotg))/OData/OData.svc/$metadata

Response:

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
    <edmx:DataServices m:DataServiceVersion="3.0" m:MaxDataServiceVersion="3.0" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
        <Schema Namespace="ODataDemo" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">

            ...

            <EntityType Name="Supplier">
                <Key>
                    <PropertyRef Name="ID" />
                </Key>
                <Property Name="ID" Type="Edm.Int32" Nullable="false" />
                <Property Name="Name" Type="Edm.String" />
                <Property Name="Address" Type="ODataDemo.Address" />
                <Property Name="Location" Type="Edm.GeographyPoint" SRID="Variable" />
                <Property Name="Concurrency" Type="Edm.Int32" ConcurrencyMode="Fixed" Nullable="false" />
                <NavigationProperty Name="Products" Relationship="ODataDemo.Product_Supplier_Supplier_Products" ToRole="Product_Supplier" FromRole="Supplier_Products" />
            </EntityType>
            <ComplexType Name="Address">
                <Property Name="Street" Type="Edm.String" />
                <Property Name="City" Type="Edm.String" />
                <Property Name="State" Type="Edm.String" />
                <Property Name="ZipCode" Type="Edm.String" />
                <Property Name="Country" Type="Edm.String" />
            </ComplexType>

                ...

            <EntityContainer Name="DemoService" m:IsDefaultEntityContainer="true">
                ...
                <EntitySet Name="Suppliers" EntityType="ODataDemo.Supplier" />
                ...
                <FunctionImport Name="GetProductsByRating" ReturnType="Collection(ODataDemo.Product)" EntitySet="Products" m:HttpMethod="GET">
                    <Parameter Name="rating" Type="Edm.Int16" Nullable="false" />
                </FunctionImport>
                <AssociationSet Name="Products_Advertisement_Advertisements" Association="ODataDemo.FeaturedProduct_Advertisement_Advertisement_FeaturedProduct">
                    <End Role="FeaturedProduct_Advertisement" EntitySet="Products" />
                    <End Role="Advertisement_FeaturedProduct" EntitySet="Advertisements" />
                </AssociationSet>
                <AssociationSet Name="Products_Categories_Categories" Association="ODataDemo.Product_Categories_Category_Products">
                    ...
                </AssociationSet>

                 ...

            </EntityContainer>
            <Annotations Target="ODataDemo.DemoService">
                <ValueAnnotation Term="Org.OData.Display.V1.Description" String="This is a sample OData service with vocabularies" />
            </Annotations>

            ...

        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

In order to get a clearer picture of the document structure, I omitted the irrelevant parts.
Introduce the focus of metadata. Metadata is used to define the data structure of odata. The following figure is from [Manual create a data model to use in SAP Web IDE's Mock Data server] (
https://www.sap.com/developer/tutorials/hcp-webide-create-odata-model.html It can explain the composition of metadata very well.

  • Data Service Vesion: Version of data service
  • EntitiContainer is generally determined to include those EntitySet s, such as northwind including Products, Suppliers and so on.
<EntityContainer Name="DemoService" m:IsDefaultEntityContainer="true">
    <EntitySet Name="Products" EntityType="ODataDemo.Product" />
    <EntitySet Name="ProductDetails" EntityType="ODataDemo.ProductDetail" />
    <EntitySet Name="Categories" EntityType="ODataDemo.Category" />
    <EntitySet Name="Suppliers" EntityType="ODataDemo.Supplier" />
    <EntitySet Name="Persons" EntityType="ODataDemo.Person" />
    <EntitySet Name="PersonDetails" EntityType="ODataDemo.PersonDetail" />
    <EntitySet Name="Advertisements" EntityType="ODataDemo.Advertisement" />

    ...

</EntityContainer>
  • Entity Set contains EntityType, such as Suppliers, which contains Supplier. Entity contains key and properties:
<EntityType Name="Supplier">
    <Key>
        <PropertyRef Name="ID" />
    </Key>
    <Property Name="ID" Type="Edm.Int32" Nullable="false" />
    <Property Name="Name" Type="Edm.String" />
    <Property Name="Address" Type="ODataDemo.Address" />
    <Property Name="Location" Type="Edm.GeographyPoint" SRID="Variable" />
    <Property Name="Concurrency" Type="Edm.Int32" ConcurrencyMode="Fixed" Nullable="false" />
    <NavigationProperty Name="Products" Relationship="ODataDemo.Product_Supplier_Supplier_Products" ToRole="Product_Supplier" FromRole="Supplier_Products" />
</EntityType>
<ComplexType Name="Address">
    <Property Name="Street" Type="Edm.String" />
    <Property Name="City" Type="Edm.String" />
    <Property Name="State" Type="Edm.String" />
    <Property Name="ZipCode" Type="Edm.String" />
    <Property Name="Country" Type="Edm.String" />
</ComplexType>

View Entity Set

Request:

Response:

{
  "odata.metadata": "http://services.odata.org/V3/(S(i2ebiza3pghgcecz3upusotg))/OData/OData.svc/$metadata#Suppliers",
  "value": [
    {
      "ID": 0,
      "Name": "Exotic Liquids",
      "Address": {
        "Street": "NE 228th",
        "City": "Sammamish",
        "State": "WA",
        "ZipCode": "98074",
        "Country": "USA"
      },
      "Location": {
        "type": "Point",
        "coordinates": [
          -122.03547668457,
          47.6316604614258
        ],
        "crs": {
          "type": "name",
          "properties": {
            "name": "EPSG:4326"
          }
        }
      },
      "Concurrency": 0
    },
    {
      "ID": 1,
      "Name": "Tokyo Traders",
      "Address": {
        "Street": "NE 40th",
        "City": "Redmond",
        "State": "WA",
        "ZipCode": "98052",
        "Country": "USA"
      },
      "Location": {
        "type": "Point",
        "coordinates": [
          -122.107711791992,
          47.6472206115723
        ],
        "crs": {
          "type": "name",
          "properties": {
            "name": "EPSG:4326"
          }
        }
      },
      "Concurrency": 0
    }
  ]
}

View a single Entity

For example, we would like to see the first supplier:

Request:
- Type: GET
- URL: http://services.odata.org/V3/(S(i2ebiza3pghgcecz3upusotg))/OData/OData.svc/Suppliers(0)/?$format=json

Response:

{
  "odata.metadata": "http://services.odata.org/V3/(S(i2ebiza3pghgcecz3upusotg))/OData/OData.svc/$metadata#Suppliers/@Element",
  "ID": 0,
  "Name": "Exotic Liquids",
  "Address": {
    "Street": "NE 228th",
    "City": "Sammamish",
    "State": "WA",
    "ZipCode": "98074",
    "Country": "USA"
  },

  ...

}

View Entity's Related Property

For example, look at the name of the first supplier:

Request:
- Type: GET
- URL: http://services.odata.org/V3/(S(i2ebiza3pghgcecz3upusotg))/OData/OData.svc/Suppliers(0)/Name?$format=json

Response:

{
  "odata.metadata": "http://services.odata.org/V3/(S(i2ebiza3pghgcecz3upusotg))/OData/OData.svc/$metadata#Edm.String",
  "value": "Exotic Liquids"
}

Know so much first, navigation properties and so on, and then talk about it later.

openui5 OData Model

Sap provides sap. ui. model. odata. OData Model, sap. ui. model. odata. v2. OData Model and sap. ui. model. odata. v4. OData Model. sap.ui.model.odata.ODataModel is out of date. odata v2 model currently supports OData 2.0. odata v4 model supports OData 4.0, but only binding mode. Code patterns are not supported and should be under development. odata v2 model is recommended.

For the changes and differences between odata v2 model and odata model, see: OData v2 Model

OData Model belongs to the server-side data model, that is, the client must request, according to the server's response, to see the requested data.

Same-origin policy

OData is a web-based protocol. Data access is restricted by the same-origin policy. What is the same-origin policy? WIKI Explanation:

In computing, the same-origin policy is an important concept in the web application security model. Under the policy, a web browser permits scripts contained in a first web page to access data in a second web page, but only if both web pages have the same origin. An origin is defined as a combination of URI scheme, hostname, and port number. This policy prevents a malicious script on one page from obtaining access to sensitive data on another web page through that page's Document Object Model.

Some examples are given to facilitate our understanding.

If we CRUD services.odata.com directly, because we violate the same-origin policy, there will be errors. Solution:

  • Use proxies, such as https://cors-anywhere.herokuapp.com/
  • In SAP Web IDE, it is proxyed by SAP Web IDE through HCP(Hana Cloud Platform) account.

Reference posts: stackoverflow: access cross origin resources

Read OData data through OData model

v2 model provides two methods, one is through code, the other is through data binding. Let's first look at how OData data can be accessed through code:

var sServiceUrl = "http://services.odata.org/V3/Northwind/Northwind.svc/";
var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl);         

sap.ui.getCore().setModel(oModel);

oModel.read("/Products(1)", {
    success: function(oData, oResponse){
        console.log(oData);
        console.log(oResponse);
    },
    error: function(oError){
        console.log(oError);
    }
})

Running the program, Chrome Browser returns the following error (F12 view)

Failed to load resource: the server responded with a status of 501 (Not Implemented)

index.html:1 XMLHttpRequest cannot load http://services.odata.org/V3/Northwind/Northwind.svc/$metadata. Response for preflight has invalid HTTP status code 501

Change var sServiceUrl = "http://services.odata.org/V3/Northwind/Northwind.svc/"; to read:

var sServiceUrl = "https://cors-anywhere.herokuapp.com/http://services.odata.org/V3/Northwind/Northwind.svc/";

oData and oResponse can be returned as normal.

The second method is to bind OData data through controls:

var sServiceUrl = "https://cors-anywhere.herokuapp.com/http://services.odata.org/V3/Northwind/Northwind.svc/";
var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl);    

sap.ui.getCore().setModel(oModel);

var oText = new sap.m.Text({
    text: "Product name: {ProductName}"
});

var oPage = new sap.m.Page("masterPage", {
    title: "Product 1 information",
    content: [oText]
});
oPage.bindElement("/Products(1)");

var oApp = new sap.m.App();
oApp.addPage(oPage);
oApp.placeAt("content");

Reference resources

RESTful API Best Practices

A Preliminary Understanding of OData

OData v2 model

[Manually creating a data model in SAP Web IDE Mock Data server](
https://www.sap.com/developer/tutorials/hcp-webide-create-odata-model.html)

Same-origin policy

Posted by mgzee on Sun, 06 Jan 2019 13:33:09 -0800