2

We have a complex fabric BPM solution. We now want to expose the fabric as set of rest APIs.

We have an application, in application we have workflows, workflow can have actions. action have fields and fields can have rules.

so right now the first set of api for fields or rules were made as

[Get] apps/1/workflows/1/actions/1/fields/4/rules

[Post]

apps/1/workflows/1/actions/1/fields/3/rules

but this doesn't look nice, these can get more complex, usually what i read is that keep the URI as simple as lean as possible, should not go in that depth.

so what should be the preferred uri for the above mentioned .

should we make fields and rules as separate resources? or how to go about it. if we make it as separate resources then how to get the specific field. won't it require lot of paramters which then again isn't that of a good approach.

edited again

What i wanted to confirm is that if making the making the deep URIs which i mentioned above is a good standard(which some ppl think is not a very good approach), but as you mentioned it is more like a choice.

So what if i don't chose to make the long URIs and keep it really lean for atleast version 1.

in the above URI example i have to give apps id, workflow id, action id and then field id to get to the required field. which will stay this way unless i have some sort of hash to identify that specific URI. so

apps/1/workflows/1/actions/1/fields/3/rules

becomes

/55667788

what if i want to keep the URIs readable yet small. e.g. Fields/ returns all the fields of app 1, workflow 1 action 1 but how to provide all those ids without making my URI so cluttered? keeping it to two levels? is it possible or am i goign in the wrong direction?

Darrel Miller
  • 139,164
  • 32
  • 194
  • 243
Waqas
  • 424
  • 7
  • 15

1 Answers1

8

Well, there's a ton to be said about this topic, but I think specifically this revolves around URI templates. I think we need to use some better examples. If you mean the example URI to be (as you say in your question) ;

apps/1/workflows/1/actions/1/fields/4/rules

Then I'd say, no, here you're introducing semantics into the URI which are not needed, specifically /workflows/ /actions/ /fields/ /rules/. You should denote a URI template for this, and I would come up with something like this ;

{application}/{workflow}/{action}/{field}/{rule}

Basically we can translate an URI such as this ;

/yalla/4356/open_portfolio

Into ;

application = 'yalla'
workflow = '4356'
action = 'open_portfolio'
field = ''
rule = ''

And just see what HTTP method was used, and apply action classes based on that. Your mileage will vary.

However, at this point I'm a bit wary of {action} because in REST we try our hardest to work with a uniform interface, but then I don't know what sort of action you're referring to. It strikes me as a more traditional RPC way of thinking, which I'd try to break free from. For example, if you have a more traditional RPC structure like this ;

/yalla/4356/create_new_portfolio

you're breaking the guaranteed safety of a GET operation (like the classical blunder of using /delete_user as action URI and then have a spider crawling your site with GET ...). Instead I'd do this ;

/yalla/4356/portfolio

To this resource I'll GET to view, PUT to update, POST to create, and DELETE to, well, delete. In that sense, the {action} part of the URI template becomes a bit muddled. What do you want the API to cover?

First rule of creating good URIs is to create URIs that match the resources in your system, and not operations and actions. I'd create resources for your portfolios, but not the actions; those I'd bake inside my GET/POST/PUT/DELETE.

Also, I'm not sure at what point you need the fine granularity of {field} and {rule}, but this is up to you. It could well be that you'd like to update just a field value, and there's nothing wrong with that. I'd probably support that myself, but also support for a climb up the structure tree, so that you could update a field ;

PUT /yalla/4356/portfolio/name?value=new_value

But also update several fields ;

PUT /yalla/4356/portfolio?name=new_name&other=something

And so on, up and down the structure of the tree. This is good practice in that you give your developers/users the flexibility to choose themselves how they would like to work with your API, which is always a bonus.

Update: More clarification follows.

Since we are talking about REST and good use of URIs, there's nothing that says that this resource ;

/yalla/4356/portfolio

Couldn't also be ;

/454A876D786F

Both of these identifiers are representing the exact same thing. Every resource in your system can get a canonical identifier and URI like that, and you can use various paths into the structure. Even this specific field ;

/yalla/4356/portfolio/53464/A4576456/title

Can also have the URI ;

/3498756A8768976FF8976

Further, about the strictness of having something like this constraining your URIs ;

{application}/{workflow}/{action}/{field}/{rule}

It is just an example. Here's several examples to get your thoughts going ;

/apps/{application}/{workflow}/{action}/{field}/{rule}
/workflows/{workflow}/{action}/{field}/{rule}
/action/{action}
/id/{id}
/api/{application}/{api}/{version}/{resource}
/property/{property}
/forms/{form}/{field}

The serious RESTafarian would not worry too much about structure in URIs. I quite often deliberately choose non-semantic identifiers for things / entities / topics, using a lot of

/3498756A8768976FF8976

for all manner of things, even relationships between things. The above URI might be; a topic, a subject, a category, a relationship, a role, a field, an action, a form, an application, and on and on it goes.

I come from the world of Topic Maps (and you can see one of my answers to something slightly different talk about it and how it works over here) in which every thing you talk about, every aspect of your model, is represented with a topic, and all topics have identifiers. (I could complicate it and state that there are three kinds of identifiers; internal, local and external, where the latter two use URIs, but I'm not sure that explain much at this point :) For example, here is a topic representing an application ;

PUT /1234 name='My app'&type='application'

This means I can talk about or refer to my application using that identifier anywhere in my system (you would normally have a cache of types handy). Create identifiers that are unique to every little thing, and the RESTful interface would be far, far easier to deal with.

As to your latest edit, I'm not quite sure I understand what you're asking there, so maybe if you provide some examples would be helpful. But do you mean if you made some of those sub-properties unique URIs in their own right? Like ;

/3498756A8768976FF8976

When you get this resource, you will get a response back. Not sure what representation you're going with, it could be XML or JSON, or HTML with embedded metadata, but let's choose XML just because the example will be simple ;

<response>
   <resource id="3498756A8768976FF8976">
      <type id="field" />
      <alias uri="some/other/path" />
      <alias uri="and/another/example" />
      <relationships>
         <parent id="4563456456" type="form" />
         <child id="5784567345" type="rule" />
         <child id="3457698786" type="rule" />
      </relationships>
   </resource>
</response>

Without knowing too much about your systems requirements, here is an example where the field (which is the <resource> with its id in it), which you can get through (and even if I say that the id is 'type', I really mean some other ambiguous id like 3459867354 that represent 'field', and the same for other id's that spell out in name; they're really just id's and spelled out for ease of understanding :), and it has a few aliases. You map in the relationships, and we can see that this field belongs to a certain form, and that it also has two rules attached. You can next query any of those id's to get metadata about where they belong and what they are and do.

You can of course extend this with documentation directly in the XML representation, examples, hints, usage, statistics, whatever else you feel people need.

But I have to say a few things about creating a RESTful system. REST clients should be able to understand forms, so if I ask for a XHTML representation (as opposed to XML above), it can contain actions available to me ;

<html>
    <body>
       <form action="/apps/1234" method="get">
          <input type="submit" title="View 1234 application" />
       </form>
       <form action="/apps/1234/567" method="get">
          <input type="submit" title="View 1234 applications' portfolio" />
       </form>
       <form action="/apps/1234" method="post">
          <input type="text" name="query" title="What to search for?" />
          <input type="submit" title="Search application 1234" />
       </form>
    </body>
</html>

A REST client can use and browse through a full application automatically based on this. There's tons of interesting things to say about this, of course, but I fear I'm going into novel mode, and perhaps outside the scope of your question, but suffice to say, if you focus on a myriad of forms being the interface into your application, you don't even have to worry about URI templates; just point to a resource, get the XHTML forms, and your API should be fairly easy to use and completely self-documented.

Second edit:

I always avoid plurals for structured access to items. For example, I would use ;

/product/345634

for a specific product, and just use ;

/product

for a list of all products. For example, to create a new product, you POST to /product, and you should get a /product/{new_id} back if successful. If you want to, you could also do ;

/product/3456345
/products

But I wouldn't recommend it. As to two levels vs. any kind of level, I don't think you should worry too much about how cluttered it's going to be. URIs that are deep in the system are rarely if ever interpreted by humans. Does it really matter if your URIs are long?

Having said that, though, of course you could do ;

/field
/workflow
/action
/application

to get to collections of those types. Again, what is the requirement of those you create this API for? If it's only for aesthetic reasons, ie. your own opinion of cluttered URIs, then I'd say you're worrying about the wrong thing. Short URIs don't necessary make your API easier to understand. I'd go with the full structured I talked about early in this answer.

Anyway, hope that helps a little, and feel free to clarify and I'll expound further.

Community
  • 1
  • 1
AlexanderJohannesen
  • 2,028
  • 2
  • 13
  • 26
  • Like you said, it's a myth. :) There's no reason to limit the structure, it all depends on the granularity you need and the what you're prepared to support. – AlexanderJohannesen Jul 07 '11 at 11:48
  • :) i mean apigee and many developers across globe suggest that it should not go beyond two levels. but i guess you are right. I am new to this and keeping the right balance between standards and requirements is bit difficult. – Waqas Jul 07 '11 at 12:07
  • what i can do is to make fields as the main resource but then how to provide all ids of(apps, workflow, actions etc) in the get then? is there some sort of good training material you can suggest @alexanderjohannesen on this sort of issue – Waqas Jul 07 '11 at 12:16
  • Also for post in most of the cases we will be posting json and for get we will be getting json. so if that can give u an idea how granular we should go. and by granularity do you mean apps,workflow, actions, fields rules each will be a separate resource? – Waqas Jul 07 '11 at 13:03
  • `{application}/{workflow}/{action}/{field}/{rule}` will lock down your resource tree to exactly on path. Otherwise, you can't detect if param 2 is for instance a `workflow` or another subresource of `application`. Also, I think the semantics of named URI parts is at least useful for humans to understand what this resource is about, without any implications on the application itself. – b_erb Jul 07 '11 at 15:01
  • Basically, it comes down to what the requirements of your API is. PartlyCloudy is right in that there's a lock there, but easily worked around by providing different structures. For example, '{application}/{workflow}/{action}/{field}/{rule}' is stricter than 'struct/{application}/{workflow}/{action}/{field}/{rule}'. I've update my answer to some of this. – AlexanderJohannesen Jul 08 '11 at 03:49
  • That was great Alexander :) thanks for the help. one small query. – Waqas Jul 08 '11 at 08:14
  • One small query, we are spliting the resources bcoz the json for the application was huge and we though it was a good idea to decrease the payload by spliting the json into the above mentioned multiple jsons(workflow, action etc).and now thinkin about providng methods to save each "resource" individually bcoz of payload. That is how we identified the resources,is it a good approach? secondly to get the resource e.g. field which is down in hierarchy whats the best apprach for providing ids for app,workflow,action? :) Field/???? how should the ids come here? – Waqas Jul 08 '11 at 08:27
  • or is it even a better way to keep the json as it is and use Field Selectors instead? something like apps/Fields:(workflow::action=5::fields) – Waqas Jul 08 '11 at 08:27
  • Yes, splitting might be good for payload, but it kinda depends on how the app at the other end are going to use it. Splitting is fine if the app gets the resources in chunks, but it might actually eat more resources if it's all at once. Is this for an AJAX application or normal web app? So, do you mean pagination in lists of resources? It probably should use some convention to soften the blow on the server (like, all default is max 10 items, but you can specify bigger) by good defaults. – AlexanderJohannesen Jul 08 '11 at 11:04
  • As to whether the structure / payload is a good way to determine resource, I'd say no, but it doesn't mean that that it can't be. It - as always - depends. I like to structure my resource so they make sense in relation to each-other. The structure you've got is a very technical one, but if that technical model also matches how the API is used by the app on the other side, there's no problem with it (and in fact might be a better fit). It depends on whether the API is for humans, clients or apps. :) – AlexanderJohannesen Jul 08 '11 at 11:05