Hi Mike I hope you understand that I'm not rejecting your proposal at all :-) just throwing balls in the air and alternative suggestions so we can reach the best solution. Tonight I am gonna review your branch in more detail and give you some feedback.
Earlier you mentioned that all you really need to describe the restful service is a list of objects. I don't entirely agree with this unless that list also contains object info ie. attribute names and types. / Jakob 2012/10/23 Mykhailo Stadnyk <[email protected]> > Initially I was supposed to implement in some kind of way, but just using > the class-level decorator. But! It is too strict and not as flexible as > could be. > I told already taht I imagine that exposing RESTful methods might be a bit > more flexible. Let's imagine that I already have some SOAP service which > is easily could map to REST by exposing the methods (assuming that SOAP > service is "almost RESTful", but all I need is to expose to HTTP GET not a > single method but several). You can look at, for example, JAX-WS - the REST > implementation is something like in my proposal. You put TOO strict > constraints for the REST service, mine is more flexible. I propose to > developer to decide what does he want to do with his service (he might want > to have 2 POST, 5 GET, 1 PUT and no DELETE HTTP methods exposed for > concrete service object). This mapping could be easily done by matching the > arguments passed through an HTTP, so the rule is a following: > 1. If you have several methods exposed to the same type of HTTP request, > which method to call is determined by matching the bypassed HTTP params and > the service method arguments > 2. REST is not RPC, so you can not tell which method to call by name, but > we can call different methods relying on their signatures > > 1,2 - the same but with different words. > > Regards, > Mike > > 2012/10/23 Jakob Simon-Gaarde <[email protected]> > >> Let's try to define the end-user result, and then discuss the >> implementation afterwards. >> >> In the following I have defined a very simple type as a case we can >> collaborate through. >> >> Maybe we have an object called Client that needs to be RESTful. I think >> the nicest thing to do would be to SubClass LadonType (ie. >> RESTfulLadonType) which has some virtual methods: >> >> class Client(RESTfulLadonType): >> >> uid = PORTABLE_STRING >> name = PORTABLE_STRING >> account = PORTABLE_STRING >> credit = bool >> >> def get(self,id): >> pass >> >> def put(self,id): >> pass >> >> def delete(self,id): >> pass >> >> Ladon sees right away that some og the objects used in the Service class >> are RESTful and adds restful to the list of protocols. >> Your turn! >> >> / Jakob >> >> >> >> 2012/10/23 Jakob Simon-Gaarde <[email protected]> >> >>> I knew this already :-) And that's not nessesarilly a bad thing, >>> depending on what you are developing. I just think we need to think through >>> how to implement it in Ladon. Since you have enjoyed using Ladon until now, >>> you probably already know that I am a hugh fan of end-user simplicity. >>> >>> And since REST is strictly object-oriented, I really think we should be >>> looking at decorating the LadonType instead of methods. I haven't thought >>> it all the way through yet, but I'm almost sure that would be the place to >>> do it. >>> >>> >>> / Jakob >>> >>> >>> 2012/10/23 Mykhailo Stadnyk <[email protected]> >>> >>>> Exacly! REST is a constraint to objects by design! You've caught it. >>>> But it's good principal for data-oriented services with no overhead by any >>>> top-level protocol. It's a principal of building RESTful services. And will >>>> be good if Ladon will support it >>>> >>>> 2012/10/23 Jakob Simon-Gaarde <[email protected]> >>>> >>>>> But, I think I know what you mean. It's the fact that it utilizes all >>>>> HTTP methods that makes you say that REST is in the HTTP protocol. I just >>>>> don't nessesarily find that this is very revolutionary. It's more of a >>>>> constraint, cause you are limited to objects by design. >>>>> >>>>> / Jakob >>>>> >>>>> >>>>> 2012/10/23 Mykhailo Stadnyk <[email protected]> >>>>> >>>>>> 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 <[email protected]> >>>>>> >>>>>>> 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 <[email protected]> >>>>>>> >>>>>>>> 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 <[email protected]> >>>>>>>> >>>>>>>>> My first question about your RESTful implementation is, why are >>>>>>>>> you not implementing it as a protocol? >>>>>>>>> >>>>>>>>> / Jakob >>>>>>>>> >>>>>>>>> 2012/10/22 Jakob Simon-Gaarde <[email protected]> >>>>>>>>> >>>>>>>>>> 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 <[email protected]> >>>>>>>>>> >>>>>>>>>>> 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 <[email protected]> >>>>>>>>>>> >>>>>>>>>>>> Hi Mike >>>>>>>>>>>> >>>>>>>>>>>> Looking into this now, you will have my reply today :-) >>>>>>>>>>>> >>>>>>>>>>>> / Jakob >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> 2012/10/22 Mykhailo Stadnyk <[email protected]> >>>>>>>>>>>> >>>>>>>>>>>>> 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 <[email protected]> >>>>>>>>>>>>> >>>>>>>>>>>>>> Interesting :-) >>>>>>>>>>>>>> >>>>>>>>>>>>>> I'll look at it later - we must make sure that it doesn't >>>>>>>>>>>>>> break anything. >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> 2012/10/22 Mykhailo Stadnyk <[email protected]> >>>>>>>>>>>>>> >>>>>>>>>>>>>>> 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 >>>>> >>>>> -- >>>>> Mailing list: https://launchpad.net/~ladon-dev-team >>>>> Post to : [email protected] >>>>> Unsubscribe : https://launchpad.net/~ladon-dev-team >>>>> More help : https://help.launchpad.net/ListHelp >>>>> >>>>> >>>> >>> >>> >>> -- >>> Med venlig hilsen / Best regards >>> Jakob Simon-Gaarde >>> >> >> >> >> -- >> Med venlig hilsen / Best regards >> Jakob Simon-Gaarde >> >> -- >> Mailing list: https://launchpad.net/~ladon-dev-team >> Post to : [email protected] >> Unsubscribe : https://launchpad.net/~ladon-dev-team >> More help : https://help.launchpad.net/ListHelp >> >> > -- Med venlig hilsen / Best regards Jakob Simon-Gaarde
-- Mailing list: https://launchpad.net/~ladon-dev-team Post to : [email protected] Unsubscribe : https://launchpad.net/~ladon-dev-team More help : https://help.launchpad.net/ListHelp

