Quantcast
Channel: Bityard
Viewing all articles
Browse latest Browse all 6

Designing for Rest Part 1 – Endpoints

$
0
0

Crazy Days

APIs are the new hotness these days. Whats amazing is that the idea of using the web in it’s native form (ie stateless) has been around for, well, a long time. I remember working on a project 14ish years ago where we stood up an ASP 3 (legacy vbscript) site to provide xml feeds to a RIA (Rich Internet App for the kids) written in Flash. I remember leveraging GET/POST to retrieve and update data and how we thought we were brilliant for coming up with this at the time. I remember also trying this later, other places (in the webforms era) and being treated like an idiot. However, proving that time is in fact cyclical (no more apparent than in IT) I am now doing this all over again, 14ish years later. Albeit with newer and better technology…but still. You get my gist. *As a side note, it is interesting that no one remembers server side javascript when Netscape introduced it eons ago…maybe I’m just old (which is probably true).

What I find most interesting this time around is the challenges that most developers face adopting this idea. REST as an idea is not complicated; REST post flash/asp.net webforms seems to be catching more than few developers off guard, even very senior ones. The idea of a session-less state and not having the safety net of some of the technologies from the past 8 or so years, coupled with that push around the same time to embrace SOA – specifically SOAP – pretty much ruined the internet for a lot of us developing business applications at an enterprise level. I’ll be honest- I hate SOAP. There, I said it. I hate WCF as well but that’s a whole other hell I could devote my life to preaching against. SOA was always misunderstood and the early adopters either caused service explosion (which they now cover up by claiming they are micro-services but there is nothing micro about them) OR were incredibly suspicious of exposing to much ergo there were only a handful of services that broke the flow of the app when 90% of the code was local. It was a maddening time.

Now, with the influx of younger developers and newer technology, along with ‘web-scale’ becoming the norm, the idea of splitting your business logic from your UI has never been more widely accepted or pushed as a more holistic goal for a business. The idea of ‘algorithms as a service’ to be consumed either externally or internally is an amazing leap forward in terms of group think; while this is a pretty beaten up topic as of late, I am currently advising on a series of very large, very visible projects for one of our largest clients- and out of that fell some general things I have shared with them that I thought I would share with anyone that wanted them. They aren’t perfect or maybe even 100% correct- but they helped an organization move forward very quickly and realize ROI at a rapid pace. More importantly, they guided some very smart people down the pretty deep hole that is XAAS (everything as a service).

Some things to put the remainder of this in context:

  • REST is technology agnostic; I will also admit some technologies adopt the idea in a more native fashion than others. To each his own, pick your poison, etc.
  • Our core stack is .NET – if I reference this, you know why. I most likely won’t…but I pointed it out anyway.
  • I do not drink the Koolaid as I have 3rd degree burns from the last time a certain Seattle company switched it out with bleach at a frat party.

Endpoints are just URLs

Well they are. Except when they aren’t.

This is probably the #1 thing I have had to spend the most time on with developers of APIs. This usually takes, on average, many hours of meetings which inevitably end with me saying ‘You know your business and your domain. What makes sense to you is what you should use.’ repeatedly until accepted. I say this because, the first thing everyone seems to glob onto is resource based URLs. Once accepting this as a thing, they tend to try to beat every single thing into a resource based URL. Here however, is the reality- not everything lends itself to a resource based URL. I do believe (and one of our tenets is) that resources should be used as often as possible. Semantically resources make sense- for example:

  • https://<some root domain>/accounts – this is clearly a list of accounts.
  • https://<some root domain>/accounts/<account id> – this is clearly a specific account

By using resources, your API becomes cohesive and self descriptive. I don’t expect to get a user from the URL /accounts. Where this breaks down with some people is when you get into what we would consider ‘functional’ endpoints as well as dealing with sub relations. For instance, I present actual examples of conversations I have had about each of these topics:

Functional Endpoint Conversation
  • Dev A: So, we have this need to actually close a transaction and link it to these other items.
  • Me: Ok….
  • Dev A: So, I figure we can just do a PUT on <some url>/orders/<order id>
  • Me: Is it order related?
  • Dev A: Yes. Well, no. I mean it could be. Really, we just put the properties on the order object for simplicity sake.
  • Me: So…it is not order related? Also you said put…are you updating an order?
  • Dev A: No it is not order related and no…we are linking this transaction. The PUT method will update the db based on these 2 properties (out of 10)
  • Me: You’re killing me.

So why is that bad? Well, it isn’t. Except that it is. Kind of. Confused? Well here are the issues:

  • PUTs should be in-place full updates of a resource.
    • If I PUT 10 properties to a URL, it should leverage 10 properties. In this case, it was leveraging 2…and those 2 were not enforced in anyway that a consumer would know they are required short of documentation. Its just a bad design…
  • It is not related to the resource in any way.
    • This seems to happen a lot honestly. A call is extended or a payload reused to speed development up. Honestly, in this case if it is transaction related it should at a minimum have been going to a /transactions/<transaction id> url…but it wasn’t. It was jammed in somewhere to get it done (see my growing hatred of Agile).
  • It is not a resource based operation
    • It is, but it is what we have been considering this bucket of ‘functional’ vs resource. In this case, a more semantic URL would have been a PUT to /transactions/<transaction id>/status with a payload of a status where the status could have been updated then items linked. Semantically, a PUT or POST to /status to update a related status makes more sense than a PUT to the resource that will only do a partial <non> update.

None of this is to say that wouldn’t work- but it wouldn’t be easily comprehended by a consumer just by looking at it. Some things cannot be forced into the resource pattern and don’t make sense there- anything that is an very specific operation, for instance. Our rule was to make as much of it resource based as possible, but then do what you need to do so it makes sense- if /transactions/<transaction id>/onfleek makes sense in your business, then do it.

Sub-relations Conversation
  • Dev A: So, we have /orders…our thought was /orders?relatedItemId=<id>
  • Me: So, in order to get an order, you need related item?
  • Dev A: In this case, yes.
  • Me: So…/item/<item id>/orders makes more sense, right?
  • Dev A: You could do it that way, but that isn’t how we do it.
  • Me: Except…uh.
  • Dev A: It just doesn’t make sense.
  • Me: Really? because its the same thing- its a related item and you need the item to even get the orders….
  • Dev A: Except…uh.

So why is this bad?

  • There is nothing wrong with using query string parameters to do sub selecting.
    • For instance
      • /orders?itemId=<item id> would return orders by that item
      • /items?orderId=<order id> would return items by that order id
  • That said- if a resource is associated with other resources, the related resources should be accessible (where applicable) as sub resources off the root resource URL – this is even more relevant when you have to have the parent resource to even get at the related resource (such as stated above)
    • For instance:
      • /item/<item id>/orders are orders related to that item
      • /orders/<order id>/items would be related items to that order

This adds to API cohesion. Sure, you can add query string parameters- and there is nothing wrong with supporting that (see Google/Facebook/Twitter/etc). However, it is also a good idea to support contextual URLs that lead to the same data and make more sense from a RESTful standpoint. Our rule was all sub-resources should be exposed where applicable, as plural nouns off the main resource URL, following the same <resources>/<resource id> format as the parent. This means all URLs can follow this pattern ad infinitum.

Stay tuned for part 2- Versioning.


Viewing all articles
Browse latest Browse all 6

Latest Images

Trending Articles





Latest Images