← Back to team overview

ladon-dev-team team mailing list archive

Re: REST implementation

 

Here is a very simple RESTful request for a client named jim. Du you still
mean to tell me that it is not using HTTP as underlying protocol?

GET /clients/jim HTTP/1.1
Host: example.com

/ Jakob


2012/10/23 Mykhailo Stadnyk <mikhus@xxxxxxxxx>

> For REST HTTP is not underlying level but the protocol itself. In terms of
> REST design of service is known, so all you need is just to describe a list
> of objects. And then for each object there is 4 operations you are able to
> perform Create (HTTP PUT), Read (HTTP GET), Update (HTTP POST) and Delete
> (HTTP DELETE). That's why in terms of REST you do not need the description.
> You have only URLs each representing the object you can do direct HTTP
> requests and you have no overhead of having some top-level protocol, etc.
> That's why I said that REST is HTTP, because there is nothing on top of
> HTTP in REST. And there is nothing to describe, only the object URLs.
>
> It means that RESTful service architecture is not as flexible as SOAP, so
> if you, as developer decided to create RESTful service it means that you
> already chosen the service architecture. It also means that not every SOAP
> service can be RESTful, but RESTful service could be delivered with SOAP.
> So you, as developer MUST decide first if you are building a RESTful
> service, if so - go ahead, make it and Ladon give you benefit to deliver
> your RESTful service throug varius different supported protocols.
>
> Again. You CAN deliver RESTful service throug SOAP/XML-RPC/JSON-WSP/etc.
> But you CAN NOT deliver abstract SOAP/XML-RPC/JSON-WSP service through REST
> if it wasn't designed as RESTful
>
> In my implementation I've tried to make everything with maximum
> flexibility, so each RESTFul service could have more than 4 CRUD methods,
> for each HTTP request method you can have as many service methods as you
> need if the service methods have different signatures (arguments)
>
> like
>
> class Service:
>     @restfulize(method="GET")
>     def get_one_record( r_id):
>          pass
>     @restfulize(method="GET")
>     def get_last_record( r_time):
>          pass
>     @restfulize(method="GET")
>     def get_all_records():
>          pass
>     @restfulize(method="GET")
>     def get_filtered_records( filters):
>          pass
>
> As you see in this example 4 service methods are bind to HTTP GET method.
> Depending of parameters bypassed through HTTP I try to determine which
> method to call, but from terms of protocol you always do
>
> GET /Service/rest?filters['name']=*bla&filters['another_key']=somevalue
> HTTP/1.1
> Host: yourservice.com
> ...
>
> The same for other HTTP methods. You can have 2 different methods for
> POST, for example for User service example you may have split User data
> update and user password update, etc..
>
> Or maybe your service may not provide some methods. Like you create the
> public read-only service, so you don't provide PUT/POST/DELETE
>
> P.S. REST does not provide the way do bypass which service method to call
> by name. REST is not RPC. You have only the Resource, it's URL and 4
> operations. It is REST.
>
> Best regards,
> Mike
>
>
> 2012/10/23 Jakob Simon-Gaarde <jakobsg@xxxxxxxxx>
>
>> Everything in Ladon is HTTP :-)
>>
>> But HTTP is just the underlying protocol, and under that is a transport
>> protocol etc.
>>
>> When I am talking about protocol in Ladon I mean service protocols like
>> soap, json-wsp and soon json-rpc which are also protocols. I would put REST
>> at this level aswell.
>>
>> I haven't really used REST before, but from what I can see it is nothing
>> more than another service protocol which utilizes the HTTP standard a bit
>> more, like using PUT,POST,GET,DELETE methods. Also it looks like there is
>> not so much constraint on how parameters are passed so they can be JSON or
>> XML or query-string.
>>
>> I don't like that there is no service description format for REST
>> services. That is kind of a key feature in Ladon, that all supported
>> protocols should be able to describe themselves.
>>
>>
>> / Jakob
>>
>> 2012/10/22 Mykhailo Stadnyk <mikhus@xxxxxxxxx>
>>
>>> What do you mean?
>>>
>>> Actually REST is HTTP in terms of protocol, so what do I need to
>>> implement? Maybe you can explain me more detailed your thought.
>>>
>>> Best regards,
>>> Mike
>>>
>>> 2012/10/22 Jakob Simon-Gaarde <jakobsg@xxxxxxxxx>
>>>
>>>> My first question about your RESTful implementation is, why are you not
>>>> implementing it as a protocol?
>>>>
>>>> / Jakob
>>>>
>>>> 2012/10/22 Jakob Simon-Gaarde <jakobsg@xxxxxxxxx>
>>>>
>>>>> Just a remark about the package name tracepyd. That might be an
>>>>> unfortunate package name, cause on that odd platform called Windows
>>>>> pyd-files are binary python modules. Just a remark :-)
>>>>>
>>>>>
>>>>> 2012/10/22 Jakob Simon-Gaarde <jakobsg@xxxxxxxxx>
>>>>>
>>>>>> Hi Mike.
>>>>>>
>>>>>> Let's talk about tracepyd first, does it solve this bug:
>>>>>>
>>>>>> https://bugs.launchpad.net/ladon/+bug/877727
>>>>>>
>>>>>> rpclib has a terribly ugly solution for this, as you can see in the
>>>>>> bug, and we want to be better than rpclib :-)
>>>>>>
>>>>>> / Jakob
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> 2012/10/22 Jakob Simon-Gaarde <jakobsg@xxxxxxxxx>
>>>>>>
>>>>>>> Hi Mike
>>>>>>>
>>>>>>> Looking into this now, you will have my reply today :-)
>>>>>>>
>>>>>>> / Jakob
>>>>>>>
>>>>>>>
>>>>>>> 2012/10/22 Mykhailo Stadnyk <mikhus@xxxxxxxxx>
>>>>>>>
>>>>>>>> Currently it's an experimental feature which is not ready to be
>>>>>>>> integrated. I didn't test it at all (keep working on it).
>>>>>>>>
>>>>>>>> So here is my personal road-map for this feature:
>>>>>>>>   1. Resolve problem with decorators dependencies (something I
>>>>>>>> described in previous message)
>>>>>>>>   2. Write tests and test the functionality
>>>>>>>>   3. I've not checked how does it deal with requests containing
>>>>>>>> multipart boundaries and binary data
>>>>>>>>   4. Not sure what to do with service description (currently I've
>>>>>>>> just removed, but have an idea we can use it to describe service any way,
>>>>>>>> even as long as REST does not specify this)
>>>>>>>>   5. Write documentation/examples
>>>>>>>>
>>>>>>>> But I'm stuck on issue #1. I want to know:
>>>>>>>>  * do you agree to add dependency in Ladon to tracepyd module or
>>>>>>>> not?
>>>>>>>>  * If not - do you agree to include tracepyd's implementation into
>>>>>>>> Ladon (not as dependency, but to place it somewhere in tools)?
>>>>>>>>  * If not - do you agree to modify @ladonize decorator
>>>>>>>> functionality to add extra-params for REST (for me its ugly).
>>>>>>>>  * If not - which ideas do you have then? :)
>>>>>>>>
>>>>>>>> I'd like to suggest to add dependency to tracepyd. Currently I have
>>>>>>>> a version locally which works fine, so I can publish this solution to my
>>>>>>>> branch to let you see.
>>>>>>>>
>>>>>>>> Thank you in advance for your time and advice,
>>>>>>>> Mike
>>>>>>>>
>>>>>>>>
>>>>>>>> 2012/10/22 Jakob Simon-Gaarde <jakobsg@xxxxxxxxx>
>>>>>>>>
>>>>>>>>> Interesting :-)
>>>>>>>>>
>>>>>>>>> I'll look at it later - we must make sure that it doesn't break
>>>>>>>>> anything.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> 2012/10/22 Mykhailo Stadnyk <mikhus@xxxxxxxxx>
>>>>>>>>>
>>>>>>>>>> Hi Jacob.
>>>>>>>>>>
>>>>>>>>>> As I told I'm trying to implement RESTful services support by
>>>>>>>>>> Ladon. The basic functionality is implemented - you can check my branch:
>>>>>>>>>> lp:~mikhus/ladon/rest<https://code.launchpad.net/~mikhus/ladon/rest> to
>>>>>>>>>> see how does it work. Here is an example of RESTful service you may run to
>>>>>>>>>> see:
>>>>>>>>>>
>>>>>>>>>> from ladon.ladonizer import ladonize, restfulize
>>>>>>>>>> from ladon.compat import PORTABLE_STRING
>>>>>>>>>> from ladon.types.ladontype import LadonType
>>>>>>>>>>
>>>>>>>>>> class User(LadonType):
>>>>>>>>>>  name = PORTABLE_STRING
>>>>>>>>>> email = PORTABLE_STRING
>>>>>>>>>> passwd = PORTABLE_STRING
>>>>>>>>>>  def __init__():
>>>>>>>>>>  self.name = ""
>>>>>>>>>>  self.email = ""
>>>>>>>>>>  self.passwd = ""
>>>>>>>>>>
>>>>>>>>>> class UserService( object) :
>>>>>>>>>>  @restfulize(method="PUT")
>>>>>>>>>>  @ladonize(str, str, str, rtype=User)
>>>>>>>>>> def newUser( self, u_name, u_email, u_passwd) :
>>>>>>>>>>  user = User() # where User is LadonType object
>>>>>>>>>> user.name   = u_name
>>>>>>>>>>  user.email  = u_email
>>>>>>>>>> user.passwd = u_passwd
>>>>>>>>>> return user
>>>>>>>>>>  @restfulize(method="GET")
>>>>>>>>>> @ladonize(int, rtype=[User])
>>>>>>>>>>  def getUser(self, u_id) :
>>>>>>>>>> return User()
>>>>>>>>>>  @restfulize(method="GET")
>>>>>>>>>> @ladonize(int, rtype=[User])
>>>>>>>>>> def getUsers(self) :
>>>>>>>>>>  return [User(), User(), User()]
>>>>>>>>>>  @restfulize(method="POST")
>>>>>>>>>>  @ladonize(int, str, str, str, rtype=User)
>>>>>>>>>> def updUser( self, u_id, u_name, u_email, u_passwd):
>>>>>>>>>>  user = User()
>>>>>>>>>> user.name   = u_name
>>>>>>>>>> user.email  = u_email
>>>>>>>>>>  user.passwd = u_passwd
>>>>>>>>>> return user
>>>>>>>>>>  @restfulize(method="DELETE")
>>>>>>>>>> @ladonize(int, rtype=bool)
>>>>>>>>>> def delUser( self, u_id) :
>>>>>>>>>>  return True
>>>>>>>>>>
>>>>>>>>>> By the way, there is at least one issue I don't know how to solve
>>>>>>>>>> better, so I want your advice.
>>>>>>>>>>
>>>>>>>>>> As you see I've implemented specific decorator to mark service
>>>>>>>>>> methods as RESTful. It's @restfulize decorator. The problem that it is
>>>>>>>>>> implemented now as:
>>>>>>>>>>
>>>>>>>>>> def restfulize( *dargs, **dkwargs):
>>>>>>>>>>  def decorator(fn):
>>>>>>>>>> * minfo = fn._ladon_method_info*
>>>>>>>>>> if 'method' in dkwargs:
>>>>>>>>>>  if not minfo.restfulize( **dkwargs):
>>>>>>>>>> raise RestfulMethodConfigMismatch( fn.func_name)
>>>>>>>>>>
>>>>>>>>>> return fn # returns ladonized method
>>>>>>>>>> return decorator
>>>>>>>>>>
>>>>>>>>>> The problem is highlighted with bold. Will be good to make this
>>>>>>>>>> decorator independent of what @ladonize defined in it's private props. But,
>>>>>>>>>> as far as "fn" here is a reference to ladon's "injector" function I have no
>>>>>>>>>> way to determine correctly which real method in which class is decorated.
>>>>>>>>>> It means that in such case I have no way to extract LadonMethodInfo
>>>>>>>>>> associated to "fn" in other way but implemented for the moment.
>>>>>>>>>>
>>>>>>>>>> The real problem is when I want to override @ladonize decorator.
>>>>>>>>>> In this case @resftulize becomes nonoperational because I loose reference
>>>>>>>>>> to "_ladon_method_info" and means that I should take care to bypass all the
>>>>>>>>>> existing private properties in 3-d party override implementation, which is
>>>>>>>>>> not good at all. So I want to have @restfulize and @ladonize implemented
>>>>>>>>>> without hard dependency between them.
>>>>>>>>>> Via global_service_collection() it's possible to do but you need
>>>>>>>>>> to determine real method function in some way.
>>>>>>>>>>
>>>>>>>>>> So I see the following ways to fix it:
>>>>>>>>>>
>>>>>>>>>> 1. Via decorator registry (Here we solved such kind of problem by
>>>>>>>>>> creating DecoratorRegistry (I've published it as
>>>>>>>>>> http://pypi.python.org/pypi/tracepyd))
>>>>>>>>>> 2. By adding REST functionality to @ladonize decorator itself, to
>>>>>>>>>> have something like:
>>>>>>>>>>     @ladonize(PORTABLE_STRING, rtype=[PORTABLE_STRING], *rest={
>>>>>>>>>> "method" : "GET", "produces": "XML" }*)
>>>>>>>>>>
>>>>>>>>>> Maybe you can point me to some other ideas you know how to
>>>>>>>>>> resolve such kind of problem.
>>>>>>>>>>
>>>>>>>>>> Best regards,
>>>>>>>>>> Mike
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> Med venlig hilsen / Best regards
>>>>>>>>> Jakob Simon-Gaarde
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Med venlig hilsen / Best regards
>>>>>>> Jakob Simon-Gaarde
>>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Med venlig hilsen / Best regards
>>>>>> Jakob Simon-Gaarde
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Med venlig hilsen / Best regards
>>>>> Jakob Simon-Gaarde
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Med venlig hilsen / Best regards
>>>> Jakob Simon-Gaarde
>>>>
>>>
>>>
>>
>>
>> --
>> Med venlig hilsen / Best regards
>> Jakob Simon-Gaarde
>>
>
>


-- 
Med venlig hilsen / Best regards
Jakob Simon-Gaarde



-- 
Med venlig hilsen / Best regards
Jakob Simon-Gaarde