3

We're currently evaluating JSONModel for our iOS app and are liking it very much so far. The thing is, we have to deal with an OData API which tends to overcomplicate things in a couple of places. For instance, when getting back a list of entities, all APIs I can think of return something simple like this:

{
  items: [
    { id => 123, name => 'foo' },
    { id => 124, name => 'bar' },
    { id => 125, name => 'baz' },
  ]
}

Unfortunately, OData gives me something more like this:

{
  d: {
    results: [
      { Item => { id => 123, name => 'foo' } },
      { Item => { id => 124, name => 'bar' } },
      { Item => { id => 125, name => 'baz' } },
    ]
  }
}

The "d" being my least problem (as we can just parse it away). But I can't figure out how to cope with the fact that every item in the list is wrapped in a hash with the item's type as the key, so that a JSONModel relationship via NSArray does not work. I could probably define JSONKeyMapper for my Item like this:

@"Item.id"   : @"id",
@"Item.name" : @"name"

but the OData standard only wraps items in their own hash structure when there are multiple items. For instance, when fetching just a single item from the OData API, I get (as expected):

{
  d: {
    results: {
      id => 123, 
      name => 'foo'
    }
  }
}

:-(

Any ideas on how to deal with this? And before anyone suggests one of the two major OData iOS clients out there: Unfortunately, they both seem to be rather unsupported and/or outdated, including the official one listed by Microsoft.

Tobi Kremer
  • 618
  • 6
  • 22

2 Answers2

1

An FYI that might turn out to answer your question:

The JSON you posted is an old JSON format of OData (now usually referred to as "JSON Verbose"). In fact, it's going away completely when OData gets formally standardized by OASIS.

Part of the reason we replaced this old format is exactly what you're running into here: it's tough to consume.

If the OData service you're talking to supports version 3 of the OData protocol, asking for "application/json" should return the new JSON format. You can be more explicit about this for asking for "application/json;odata=minimalmetadata". The new JSON format does not have any "d" wrapper and is structured like the JSON you expected at the top of your question.

If the service you're talking to does not support V3, and you don't control the service yourself, I'll leave it to someone else to help with the Objective-C you need to work around this. If you do control the service (or can nag the person who does), I would recommending updating the service to support V3.

Jen S
  • 4,465
  • 1
  • 32
  • 28
  • Thanks for the insight, Jen! – Tobi Kremer Aug 09 '13 at 08:59
  • Unfortunately, AFAICT OData v3 still wraps expanded properties into their own respective hash structure which indeed makes it tough to consume with standard ORM libraries like JSONModel or even RestKit. Too bad that there are working OData reference implementations for almost all major languages and the official iOS client library doesn't even compile with recent iOS versions, the last time I checked. – Tobi Kremer Aug 09 '13 at 10:02
  • I think you're mistaken. OData v3 does *not* wrap expanded properties into their own hash structure. I just ran the tutorial below and it works like a charm. Nice clean JSON. http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v3/creating-an-odata-endpoint – John Henckel Dec 11 '14 at 15:47
0

Without going into too much details in understanding why OAuth does what you describe, here's how I would approach this.

  1. Make "results" an Optional property.
  2. Add an accessor method (let's say) "resultsBetter" to simulate a new readonly property on your model class
  3. Make a -(id)resultsBetter method check the type of "results" value the first time you access the method and return a either a JSONModel instance matching 1 result, or an array with more JSONModel instances (or if you need only the first one in the array you can return also only 1 object) ...

Anyways, my point is that you do not need to parse everything in one shot. You can also do that upon first access of the property in a custom accessor method. Or if you really want to do some funky setup, you can also implement a custom initWithDictionary:error: method and add some extra logic at the end of the instance initialisation.

Marin Todorov
  • 6,377
  • 9
  • 45
  • 73
  • Thanks! Thankfully we got rid of the OData bloat altogether and are now striving for an API that's easier to consume, hence making my problem obsolete. ;-) – Tobi Kremer Jan 03 '14 at 08:32