Mark Moissette
Mark Moissette

Reputation: 169

Python object hierarchy, and REST resources?

I am currently running into an "architectural" problem in my Python app (using Twisted) that uses a REST api, and I am looking for feedback.

Warning ! long post ahead!

Lets assume the following Object hiearchy:

class Device(object):
  def __init__():
    self._driver=Driver()
    self._status=Status()
    self._tasks=TaskManager()

  def __getattr__(self, attr_name):
    if hasattr(self._tasks, attr_name):
        return getattr(self._tasks, attr_name)
    else:
        raise AttributeError(attr_name)

 class Driver(object):
   def __init__(self):
     self._status=DriverStatus()

   def connect(self):
      """some code here""" 

   def disconnect(self):
     """some code here"""

 class DriverStatus(object):
   def __init__(self):
     self._isConnected=False
     self._isPluggedIn=False

I also have a rather deep object hiearchy (the above elements are only a sub part of it) So, right now this gives me following resources, in the rest api (i know, rest isn't about url hierarchy, but media types, but this is for simplicity's sake):

/rest/environments

/rest/environments/{id}

/rest/environments/{id}/devices/

/rest/environments/{id}/devices/{deviceId}

/rest/environments/{id}/devices/{deviceId}/driver

/rest/environments/{id}/devices/{deviceId}/driver/driverstatus

I switched a few months back from a "dirty" soap type Api to REST, but I am becoming unsure about how to handle what seems like added complexity:

  1. Proliferation of REST resources/media types : for example instead of having just a Device resource I now have all these resources:

    • Device
    • DeviceStatus
    • Driver
    • DriverStatus

    While these all make sense from a Resfull point of view, is it normal to have a lot of sub resources that each map to a separate python class ?

  2. Mapping a method rich application core to a Rest-Full api : in Rest resources should be nouns, not verbs : are there good rules /tips to inteligently define a set of resources from a set of methods ? (The most comprehensive example I found so far seems to be this article)

  3. Api logic influencing application structure: should an application's API logic at least partially guide some of its internal logic, or is it good practice to apply separation of concerns ? Ie , should I have an intermediate layer of "resource" objects that have the job of communicating with the application core , but that do not map one to one to the core's classes ?

  4. How would one correctly handle the following in a rest-full way : I need to be able to display a list of available driver types (ie class names, not Driver instance) in the client : would this mean creating yet another resource like "DriverTypes" ?

These are rather long winded questions, so thanks for your patience, and any pointers, feedback and criticism is more than welcome !


To S.Lott:

Upvotes: 1

Views: 2061

Answers (2)

S.Lott
S.Lott

Reputation: 391972

Rule 1. REST is about objects. Not methods.

The REST "resources" have become too fragmented

False. Always false. REST resources are independent. They can't be "too" fragmented.

instead of having just a Device resource I now have all these resources:

Device DeviceStatus Driver DriverStatus

While these all make sense from a [RESTful] point of view, is it normal to have a lot of sub resources that each map to a separate python class ?

Actually, they don't make sense. Hence your question.

Device is a thing. /rest/environments/{id}/devices/{deviceId}

It has status. You should consider providing the status and the device information together as a single composite document that describes a device.

Just because your relational database is normalized does not mean your RESTful objects need to be precisely as normalized as your database. While it's simpler (and many frameworks make it very, very simple to do this) it may not be meaningful.

consider the connection to be always existing, hence the use of "PUT" , but would that be bad thing considering "PUT" should be idempotent ?

Connections do not always exist. They may come and go.

While a relational database may have a many-to-many association table which you can UPDATE, that's a peculiar special case that doesn't really make much sense outside the world of DBA's.

The connection between two RESTful things is rarely a separate thing. It's an attribute of each of the RESTful things.

It's perfectly unclear what this "connection" thing is. You talk vaguely about it, but provide no details.

Lacking any usable facts, I'll guess that you're connecting devices to drivers and there's some kind of [Device]<-[Driver Status]->[Driver] relationship. The connection from device to driver can be a separate RESTful resource.

It can just as easily be an attribute of Device or Driver that does not actually have a separate, visible, RESTful resource.

[Again. Some frameworks like Django-Piston make it trivial to simple expose the underlying classes. This may not always be appropriate, however.]

are there good rules /tips to inteligently define a set of resources from a set of methods ?

Yes. Don't do it. Resources aren't methods. Pretty much that's that.

If you have a lot of methods -- outside CRUD -- then you may have a data model issue. You may have too few classes of things expressed in your relational model and too many stateful updates of things.

Stateful objects are not inherently evil, but they need to be examined critically. In some cases, a PUT to change status of an object perhaps should have been a POST to add to the history of an object. The "current" state is the last thing POSTed.

Also.

You don't have to trivialize each resource as a class of things. You can have resources which are collections. You can POST a fairly complex document to a composite (properly a Facade) "resource". That complex document can imply several CRUD operations in the database.

You're wandering away from simple RESTful. Your question remains intentionally murky. "method rich application core" doesn't mean much. Without concrete examples, it's impossible to imagine.

Api logic influencing application structure

If these are somehow different, you're probably creating needless, no-value complexity.

is it good practice to apply separation of concerns ?

Always. Why ask?

a lot of this seems to come from my confusion about how to map a rather method rich api to a Rest-Full one , where resources should be nouns, not verbs : so when is it wise to consider an element a rest "resource"?

A resource is defined by your problem domain. It's usually something tangible. The methods (as in "method-rich API" are usually irrelevant. They're CRUD (Create, Retrieve, Update, Delete) operations. If you have something that's not essentially CRUD, you have to STOP coding. STOP writing code, and rethink the API to make it CRUD-like.

CRUD - Create-Retrieve-Update-Delete maps to REST's POST-GET-PUT-DELETE. If you can't recast your problem domain into those terms, stop coding. Stop coding until you get to CRUD rules.

i need to be able to display a list of available driver types (ie class names, not Driver instance) in the client : would this mean creating yet another resource like "DriverTypes" ?

Correct. They're already part of your problem domain. You already have this class defined. You're just making it available through REST.


Here's the point. The problem domain has real-world objects. You have class definitions. They're tangible things. REST transfers the state of those tangible things.

Your software may have intangible things like "associations" or "links" or "connections" other junk that's part of the software solution. This junk doesn't matter very much. It's implementation detail. Not real-world things.

An "association" is always visible from both of the two real-world RESTful resources. One resource may have an foreign-key like reference that allows the client to do a RESTful fetch of another, related object. Or a resource may have a collection of other, related objects, and a single GET retrieves an object and a collection of related objects.

Either way, the real-world RESTful resources are what's available. The relationship is merely implied. Even if it's a physical many-to-many database table -- that doesn't mean it must be exposed. [Again. Some frameworks make it trivially easy to expose everything. This isn't always good.]

Upvotes: 4

wberry
wberry

Reputation: 19367

You can represent the path portion /rest with a Site object, but environments in the path must be a Resource. From there you have to handle the hierarchy yourself in the render_* methods of environments. The request object you get will have a postpath attribute that gives you the remainder of the path (i.e. after /rest/environments). You'll have to parse out the id, detect whether or not devices is given in the path, and if so pass the remainder of the path (and the request) down to your devices collection. Unfortunately, Twisted will not handle this decision for you.

Upvotes: 0

Related Questions