---
schema_version: "1"
id: c596385631eb41f4b280fc05ba28e83e1822231acfd8a8cdecbd10d42957aad3
title: Building, Implementing, and Testing an OData V4 API
collection: mulesoft
version: current
locale: en-us
portal_url: https://docs.salesforce.com/mulesoft/current/en-us/apikit/latest/creating-an-odatav4-api-with-apikit.md
canonical_url: https://docs.mulesoft.com/apikit/latest/creating-an-odatav4-api-with-apikit
source_site: docs.mulesoft.com
content_type: documentation
content_hash: 5cc9b0d33baf1a2ee740e2fa597e329d279178e4bce48d6cea2edda1864bc962
description: MuleSoft Documentation Site
release: 4.x
latest: true
---
---
product: APIkit
version: 4.x
is-latest-version: true
---

# Building, Implementing, and Testing an OData V4 API

> For the full documentation index, see: https://docs.mulesoft.com/llms.txt

Build an OData v4 API with APIkit for OData using CSDL metadata, scaffolding, and the
[OData MySQL example](#apikit-for-odata-4-implementation-example) to query MySQL over HTTP. The
tutorial covers project setup, generated flows, and running the packaged sample.

## Before You Begin

Install this software to create and use an OData REST API with APIkit:

- OData Plugin

- Mule runtime engine 4.3.0 or later

- Anypoint Studio 7.9.0 or later

Additionally, you must download the
[OData 4 implementation example](https://docs.mulesoft.com/apikit/latest/_attachments/apikit-odata4-example.jar).

## Scaffold an OData V4 API Using APIkit for OData

1.  In Studio, select **File** > **New** > **Mule Project**.

2.  In the **Project Name** field, type the name of your Mule project.

3.  Click **Finish**.

4.  In `src/main/resources/api`, create a new file with a `.csdl.xml` extension.

    For example, `odata-metadata.csdl.xml`:

    ```xml
    <?xml version="1.0" encoding="UTF-8"?>
    <edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
      <edmx:DataServices>
        <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="odata4.namespace">
          <EntityType Name="Customers"> (1)
            <Key> (2)
              <PropertyRef Name="CustomerID" />
            </Key>
            <Property Name="CompanyName" Type="Edm.String" MaxLength="40" Unicode="false" />
            <Property Name="ContactName" Type="Edm.String" MaxLength="30" Unicode="false" />
            <Property Name="ContactTitle" Type="Edm.String" MaxLength="30" Unicode="false" />
            <Property Name="CustomerID" Type="Edm.String" Nullable="false" MaxLength="5" Unicode="false" />
            <NavigationProperty Name="Orders" Type="Collection(odata4.namespace.Orders)"/>
          </EntityType>
          <EntityType Name="Orders">
            <Key>
              <PropertyRef Name="OrderID" />
              <PropertyRef Name="ShipName" />
            </Key>
            <Property Name="Freight" Type="Edm.Decimal" Precision="19" Scale="4" />
            <Property Name="OrderDate" Type="Edm.DateTimeOffset" Unicode="false" />
            <Property Name="OrderID" Type="Edm.Int32" Nullable="false" Unicode="false" />
            <Property Name="CustomerID" Type="Edm.String" MaxLength="5"/>
            <Property Name="Price" Type="Edm.Single" Unicode="false" />
            <Property Name="Priority" Type="Edm.Int16" Unicode="false" />
            <Property Name="ShipAddress" Type="Edm.String" MaxLength="60" Unicode="false" />
            <Property Name="ShipName" Type="Edm.String" Nullable="false" MaxLength="40" Unicode="false" />
            <NavigationProperty Name="Customer" Type="odata4.namespace.Customers">
            	<ReferentialConstraint Property="CustomerID" ReferencedProperty="CustomerID" />
            </NavigationProperty>
          </EntityType>
          <EntityContainer Name="OData4EntityContainer"> (3)
            <EntitySet Name="Customers" EntityType="odata4.namespace.Customers"> (4)
            	<NavigationPropertyBinding Path="Orders" Target="Orders"/>
            </EntitySet>
            <EntitySet Name="Orders" EntityType="odata4.namespace.Orders"/>
          </EntityContainer>
        </Schema>
      </edmx:DataServices>
    </edmx:Edmx>
    ```

    <table><tbody><tr><td><i data-value="1"></i><b>1</b></td><td><code>EntityType</code> defines the type and its properties.</td></tr><tr><td><i data-value="2"></i><b>2</b></td><td><code>key</code> defines which property or set of properties is the key for the entity.<div><p>For example, the entity set <code>Orders</code> comprises two keys: <code>OrderID</code> and <code>ShipName</code>.</p></div></td></tr><tr><td><i data-value="3"></i><b>3</b></td><td><code>EntityContainer</code> defines the sets of exposed entities.<div><p>In this example, <code>Orders</code> and <code>Customers</code>.</p></div></td></tr><tr><td><i data-value="4"></i><b>4</b></td><td><code>EntitySet</code> contains a name and EntityType.<div><p>You must define them in the <code>schema</code> namespace.</p></div></td></tr></tbody></table>

5.  In the **Package Explorer**, right-click your `odata-metadata.csdl.xml` file and select
    **Generate Mule OData 4 API**:

    ![The path to the Generate Mule OData 4 API option highlighted](/mulesoft/current/en-us/apikit/latest/_images/generate-odata-v4-api.png)

6.  APIkit generates the corresponding flows based on your `.csdl.xml` metadata file.

    ![The three flows created from the \`csdl.xml\` metadata file are highlighted.](/mulesoft/current/en-us/apikit/latest/_images/generated-odata-4-flow.png)

    <table><tbody><tr><td><i data-value="1"></i><b>1</b></td><td>The main flow receives messages and routes the operation to the correct handler.</td></tr><tr><td><i data-value="2"></i><b>2</b></td><td>Five flows with <code>GET</code>, <code>PUT</code>, <code>POST</code>, and <code>DELETE</code> operations for each entity.</td></tr><tr><td><i data-value="3"></i><b>3</b></td><td>A flow with a <code>GET</code> operation to retrieve the collection of entities.</td></tr></tbody></table>

## Handle OData System Query Options

Within each **On Entity Request** and **On Entity Collection Request** listener you can access a
`systemQueryOptions` attribute that maps to each OData query option (`$select`, `$orderby`,
`$count`, etc.). For example, to access the `$select` value you use the following expression:

```none
#[attributes.odataRequestAttributes.systemQueryOptions.select]
```

![odataRequestAttributes highlighted in the output tab, within the Mule message, under attributes](/mulesoft/current/en-us/apikit/latest/_images/odata-query-option-attributes.png)

## APIkit for OData 4 Implementation Example

1.  Download the full [apikit-odata4-example](https://docs.mulesoft.com/apikit/latest/_attachments/apikit-odata4-example.jar).

2.  Import the downloaded example in Studio.

3.  Run the SQL statements in the src/main/resources/example.sql file to create the database,
    tables, and test data in MySQL database.

4.  Run the application in Studio.

After Studio deploys the application, you can query your OData service using the following query
examples:

### GET Request Example

Request

```curl
curl --location --request GET 'localhost:8081/api/Customers('BLAUS')'
```

Response

```JSON
{
  "@odata.context": "http://localhost:8081/api/$metadata#Customers/$entity",
  "CompanyName": "Blauer See Delikatessen",
  "ContactName": "Hanna Moos",
  "ContactTitle": "Sales Representative",
  "CustomerID": "BLAUS"
}
```

#### GET Request Example With Composite Key

Request

```curl
curl --location --request GET 'localhost:8081/api/Orders(OrderID=10315,ShipName='Island Trading')
```

Response

```JSON
{
  "@odata.context": "http://localhost:8081/api/$metadata#Orders/$entity",
  "Freight": 41.76,
  "OrderDate": "1996-09-26T00:00:00Z",
  "OrderID": "10315",
  "Price": null,
  "Priority": 1,
  "ShipAddress": "Garden house Crowther Way",
  "ShipName": "Island Trading"
}
```

### Create Example

In this example, the client provides the key (or keys) to create a new entity:

POST Customer Request

```curl
curl --location --request POST 'http://localhost:8081/api/Customers' \
--header 'Content-Type: application/json' \
--data-raw '{
   "CompanyName": "Mulesoft",
   "ContactName": "Customer 123",
   "CustomerID": "NW123"
}'
```

POST Order

```curl
curl --location --request POST 'http://localhost:8081/api/Orders' \
--header 'Content-Type: application/json' \
--data-raw '{
   "Freight": 32.38,
   "OrderID": 100000,
   "ShipAddress": "Unknown St. 123",
   "ShipName": "Order 100000"
}'
```

### Update Example

OData V4 recommends using PATCH to update entities because it only changes the provided fields:

PATCH

```curl
curl --location --request PATCH 'http://localhost:8081/api/Customers('\''BOTTM'\'')' \
--header 'Content-Type: application/json' \
--data-raw '{
   "ContactName": "James Bottom"
}'
```

```curl
curl --location --request PATCH 'http://localhost:8081/api/Orders(OrderID=10251,ShipName='\''Victuailles en stock'\'')' \
--header 'Content-Type: application/json' \
--data-raw '{
   "ShipAddress": "Unknown Av. 1234"
}'
```

OData V4 discourages the usage of PUT to update your entities because PUT replaces the entire entity
with the new one, which can lead to data loss.

PUT

```curl
curl --location --request PUT 'http://localhost:8081/api/Customers('\''LONEP'\'')' \
--header 'Content-Type: application/json' \
--data-raw '{
   "CompanyName": "New Lonesome Pine Restaurant",
   "ContactName": "Fran C. Wilson",
   "CustomerID": "LONEP"
}'
```

```curl
curl --location --request PUT 'http://localhost:8081/api/Orders(OrderID=11056,ShipName='\''Eastern Connection'\'')' \
--header 'Content-Type: application/json' \
--data-raw '{
   "Freight": 27.52,
   "OrderDate": "1998-05-28T00:00:00",
   "OrderID": 11056,
   "Priority": 2,
   "ShipAddress": "45 King George",
   "ShipName": "Eastern Connection"
}'
```

### Delete Example

To delete the entity:

DELETE

```curl
curl --location --request DELETE 'http://localhost:8081/api/Customers('\''NW123'\'')'
```

```curl
curl --location --request DELETE 'http://localhost:8081/api/Orders(OrderID=11056,ShipName='\''Eastern Connection'\'')'
```

### Client-Side Pagination in APIkit for OData 4

You can configure your client to request the page using the HTTP query parameters `$skip` and
`$top`.

- The `$top` system query parameter specifies a non-negative integer _n_ that limits the number of
  items returned from a collection.

- The `$skip` system query parameter specifies a non-negative integer _n_ that excludes the first
  _n_ items of the queried collection from the result.

For example:

```curl
curl -X GET ‘localhost:8081/api/Customers?$skip=1&$top=5’
```

Returns five records starting from the second position.

### Server-Side Pagination in APIkit for OData 4

Server-side pagination enables you to control a subset of data requests fetched from a client-side
server by using a fixed `pageSize` parameter. It divides the response data set into discrete pages
to improve data readability. The server defines the page size, which is the maximum number of
records that the server returns in a request.

#### Server-Side Pagination Operation in OData 4

OData defines a `@odata.nextLink` to indicate that a response is only a subset of the requested
collection of entities. As such, `@odata.nextLink` contains a URL that enables the client to
retrieve the next subset of the requested collection. The URL contains a query parameter
`$skiptoken` that indicates the server where the next page starts.

#### Implement Server-Side Pagination in APIkit for OData 4

You can implement the server-side pagination by defining a set of fields with
`<apikit-odata:request-entity-collection-listener>` in the **Responses** tab in Anypoint Studio.

![pageSize set to ${service.orders.pageSize} in the On Entity Collection Request tab](/mulesoft/current/en-us/apikit/latest/_images/pagesize.png)

After `pageSize` is populated, APIkit creates the XML representation of the previous fields:

```xml
<apikit-odata:request-entity-collection-listener config-ref="odata-metadata-config" path="/Orders" method="GET" >
        <apikit-odata:collection-success-response >
            <apikit-odata:entity-collection-success-response pageSize="${service.orders.pageSize}"/>
        </apikit-odata:collection-success-response>
    <apikit-odata:request-entity-collection-listener>
```

#### Page Size or Token Fields for Server-Side Pagination

`Page size` is a fixed number that represents the maximum number of records the
`request-entity-collection` listener can retrieve for each request. In case you cannot use a numeric
pagination, set a token in the `Token field`, so a developer can generate it in the corresponding
flow. APIkit for OData includes this token value in the `@odata.nextLink` URL with a query parameter
`$skiptoken=<Token_Value>`.

## See Also

- [APIkit for OData v4 Module Reference](https://docs.mulesoft.com/apikit/latest/apikit-odatav4-extension-reference)

- [APIkit for OData v4 Error Handling Reference](https://docs.mulesoft.com/apikit/latest/apikit-odatav4-error-handling-reference)

- [Deploy to CloudHub](https://docs.mulesoft.com/cloudhub/deploying-to-cloudhub)
