6

A coworker and I are in a heated debate regarding the design of a REST service. For most of our API, GET calls to collections return something like this:

GET /resource
[
    { "id": 1, ... },
    { "id": 2, ... },
    { "id": 3, ... },
    ...
]

We now must implement a call to a collection of properties whose identifying attribute is "name" (not "id" as in the example above). Furthermore, there is a finite set of properties and the order in which they are sent will never matter. The spec I came up with looks like this:

GET /properties
[
    { "name": "{PROPERTY_NAME}", "value": "{PROPERTY_VALUE}", "description": "{PROPERTY_DESCRIPTION}" },
    { "name": "{PROPERTY_NAME}", "value": "{PROPERTY_VALUE}", "description": "{PROPERTY_DESCRIPTION}" },
    { "name": "{PROPERTY_NAME}", "value": "{PROPERTY_VALUE}", "description": "{PROPERTY_DESCRIPTION}" },
    ...
]

My coworker thinks it should be a map:

GET /properties
{
    "{PROPERTY_NAME}": { "value": "{PROPERTY_VALUE}", "description": "{PROPERTY_DESCRIPTION}" },
    "{PROPERTY_NAME}": { "value": "{PROPERTY_VALUE}", "description": "{PROPERTY_DESCRIPTION}" },
    "{PROPERTY_NAME}": { "value": "{PROPERTY_VALUE}", "description": "{PROPERTY_DESCRIPTION}" },
    ...
}

I cite consistency with the rest of the API as the reason to format the response collection my way, while he cites that this particular collection is finite and the order does not matter. My question is, which design best adheres to RESTful design and why?

AndyPerlitch
  • 4,539
  • 5
  • 28
  • 43

4 Answers4

5

IIRC how you return the properties of a resource does not matter in a RESTful approach.

http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm

From an API client point of view I would prefer your solution, considering it is explicitly stating that the name of a property is XYZ.

Whereas your coworkers solution would imply it is the name, but how would I know for sure (without reading the API documenation). Try not to assume anything regarding your consuming clients, just because you know what it means (and probably is easy enough to assume to what it means) it might not be so obvious for your clients.

And on top of that, it could break consuming clients if you are ever to decide to revert that value from being a name back to ID. Which in this case you have done already in the past. Now all the clients need to change their code, whereas they would not have to in your solution, unless they need the newly added id (or some other property).

Kay Tsar
  • 1,428
  • 11
  • 14
1

To me the approach would depend on how you need to use the data. Are the property names known before hand by the consuming system, such that having a map lookup could be used to directly access the record you want without needing to iterate over each item? Would there be a method such as...

GET /properties/{PROPERTY_NAME}

If you need to look up properties by name and that sort of method is NOT available, then I would agree with the map approach, otherwise, I would go with the array approach to provide consistent results when querying the resource for a full collection.

Mike Brant
  • 70,514
  • 10
  • 99
  • 103
1

A bit late to the party, but for whoever stumbles upon this with similar struggles... I would definitely agree that consistency is very important and would generally say that an array is the most appropriate way to represent a list. Also APIs should be designed to be useful in general, preferably without optimizing for a specific use-case. Sure, it could make implementing the use-case you're facing today a bit easier but it will probably make you want to hit yourself when you're implementing a different one tomorrow. All that being said, of course for quite some applications the map-formed response would just be easier (and possibly faster) to work with. Consider:

GET /properties
[
    { "name": "{PROPERTY_NAME}", "value": "{PROPERTY_VALUE}", "description": "{PROPERTY_DESCRIPTION}" },
    ...
]

and

GET /properties/*
{
    "{PROPERTY_NAME}": { "value": "{PROPERTY_VALUE}", "description": "{PROPERTY_DESCRIPTION}" },
    ...
}

So / gives you a list whereas /* gives you a map. You might read the * in /* as a wildcard for the identifier, so you're actually requesting the entities rather than the collection. The keys in the response map are simply the expansions of that wildcard. This way you can maintain consistency across your API while the client can still enjoy the map-format response when preferred. Also you could probably implement both options with very little extra code on your server side.

SFG
  • 143
  • 1
  • 12
0

I think returning a map is fine as long as the result is not paginated or sorted server side.

If you need the result to be paginated and sorted on the server side, going for the list approach is a much safer bet, as not all clients might preserve the order of a map.

In fact in JavaScript there is no built in guarantee that maps will stay sorted (see also https://stackoverflow.com/a/5467142/817385).

The client would need to implement some logic to restore the sort order, which can become especially painful when server and client are using different collations for sorting. Example

// server sent response sorted with german collation
var map = {
    'รค':{'first':'first'},
    'z':{'second':'second'}
}

// but we sort the keys with the default unicode collation algorigthm
Object.keys(map).sort().forEach(function(key){console.log(map[key])})

// Object {second: "second"}
// Object {first: "first"}
Community
  • 1
  • 1
Zounadire
  • 1,496
  • 2
  • 18
  • 38