codeburst

Bursts of code to power through your day. Web Development articles, tutorials, and news.

Follow publication

So What is OData Anyway?

Exploring a use case for OData and implementing a simple TypeScript example.

The example we develop in this article is available for download.

Have you heard about OData?

OData (Open Data Protocol) is an ISO/IEC approved, OASIS standard that defines a set of best practices for building and consuming RESTful APIs. OData helps you focus on your business logic while building RESTful APIs without having to worry about the various approaches to define request and response headers, status codes, HTTP methods, URL conventions, media types, payload formats, query options, etc.

— OData — OData

If you are a full stack JavaScript developer like me, probably not. This is because OData, developed by Microsoft in 2007, became popular in the enterprise crowd with the likes of Microsoft, SAP, CA, IBM, and Salesforce. The most popular implementations being on .NET and Java; not JavaScript.

The JavaScript community instead has broadly adopted an alternative solution for standardized APIs: GraphQL. Developed internally at Facebook in 2012, before public release in 2015, GraphQL is a data query language deployed at companies such as Facebook, Shopify and Intuit.

As a point of comparison, we compare the popularity of the top JavaScript libraries for GraphQL and OData.

13,240 to 40 stars; that is a big difference!

So Why Bother?

Just recently, we came across a situation where we needed to create an API to be consumed by an enterprise system; in particular Salesforce using Salesforce Connect:

Salesforce Connect provides seamless integration of data across system boundaries by letting your users view, search, and modify data that’s stored outside your Salesforce org. For example, perhaps you have data that’s stored on premises in an enterprise resource planning (ERP) system. Instead of copying the data into your org, you can use external objects to access the data in real time via web service callouts.

— Salesforce — Salesforce Connect

The problem is that without OData, we would have had to create custom Salesforce (Apex) code to consume the API. With OData, we can simply configure the integration.

The Example

We will walk through building an example that allows for create, read, update, and delete (CRUD) operations on Todo objects.

A sample read operation:

The supporting meta data:

Observations:

  • The OData syntax, while readable, is fairly verbose
  • The meta data is what allows tools like Salesforce Connect to consume the API simply with configuration
  • We will want to use a library, e.g., odata-v4-server, to do much of the heavy lifting in scaffolding the API

Prerequisites

The example is written with Node.js (10.15.3), Express, and TypeScript and is built off a starter project documented in Tech Stack 2019: Core.

Installation

Building off tech-stack-2019-backend, we first install the dependencies:

npm install odata-v4-server

Because odata-v4-server uses decorator syntax, we need to update the TypeScript configuration to support it: tsconfig.json:

{
"compilerOptions": {
...
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
...
}

Also, it turns out that odata-v4-server is not currently well supported and has a bug (unaddressed since late 2018) when used with newer versions of Node.js.

We can address this bug by patching the library with a postinstall script; updating package.json:

{
...
"scripts": {
"postinstall": "sh scripts/postinstall.sh",
...
},
...
}

and creating scripts/postinstall.sh:

note: Given that odata-v4-server does not appear to be supported going forward, a better approach would be to fork the project.

Sample Data

For this example, we will create an in-memory database to persist the Todos. In practice, however, one would likely persist objects using an actual database, e.g., PostgreSQL, MySQL, or Mongo.

We implement this in src/todo.ts:

Observations:

  • This implementation is rather long; in practice one would be using an ORM, e.g., TypeORM to persist objects
  • Also, this has nothing to do with OData itself; it is simply an in-memory database that supports create, read, update, and delete (CRUD) operations
  • In order to simulate persisting to an actual database, the operations are asynchronous; they return Promises

The Implementation

The odata-v4-server documentation, unfortunately, is non-existent; there is just a tutorial to follow. Luckily, the library is fairly straightforward to use:

We first create the model (or schema) for a Todo:

src/MyODataServer/models/Todo.ts

Observations:

  • TSLint does not like properties not named in camelCase and _id seems to be a common name for identifiers in OData

We then create the controller (implementation) for Todos:

src/MyODataServer/controllers/TodosController.js

Observation:

  • Discovered that odata-v4-server has a bug; returns a 500 error if the body in the insert and update methods is anything other than a non-empty object. As this is an unusual edge case, I did not worry about addressing it

We then assemble all the controllers (in this case, one) into a server:

src/MyODataServer/index.ts

Finally, we use the server in our Express application:

src/server.ts

...
import MyODataServer from './MyODataServer';
...
app.use('/odata', MyODataServer.create());
...

Wrap Up

While I am uncomfortable building solutions with unpopular and unsupported libraries, I found odata-v4-server to be a reasonable starting point for building a JavaScript OData API.

At the same time, I am only using OData when the situation absolutely demands it. I have been and will be happily using GraphQL, specifically Apollo GraphQL, when building APIs when given the choice.

Sign up to discover human stories that deepen your understanding of the world.

Published in codeburst

Bursts of code to power through your day. Web Development articles, tutorials, and news.

Written by John Tucker

Broad infrastructure, development, and soft-skill background

No responses yet

Write a response