(Foto by Very Good With Computers)
Why using Soap? Soap is so complex and so heavy to implement, to test and to deploy. You have an alternative: you can use REST. It is not a brand new protocol. REST was already here, from the beginning of the Web. You don't trust me? Read this.
In very few words, every web application can be designed around a good data definition and on 4 fundamental operations: create new data, edit existing data, read data, delete data. You can trust me: you have these operations in HTTP: POST, PUT, GET and DELETE. Your data may represent orders, user profiles, bookings and they are usually defined in XML. Or not? In some cases other formats can be used more convenientely. For instance JSON if your client is a web browser. JSON is a format that uses Javascript literals to serialize data. Moreover, Javascript and Python have some syntax in common. Expression like these:
a={“x”:32 , “y”:25}
b=[23,33, “I'm a string”]
c=[[34,35,36],[44, “s”]]
... are valid both in Python and Javascript. This fact suggests that with a little effort we can write web applications using Python in the server side and Ajax in the client side.
Let's see an example. We can build a very simple web service to manage a list of people. The operations are: create a user, see a user profile, remove a user. To do that we need two URLs and the 4 HTTP methods.
to be used only in GET
http://myserver/user?name=davide
where
POST creates a new user davide
GET reads the profile of davide
PUT modify the record for user davide
DELETE remove the user davide from the list
Here you have the code, that depends on Twisted.
To test GET and POST you can use a HTML form. To test PUT and DELETE you need to make some Ajax call or to use another client able to implement these methods.
from twisted.internet import reactor
from twisted.web import server, resource
from twisted.web.static import File
user1={"name":"john", "surname":"smith", "age":23, "email":"john@foo.bar"}
user2={"name":"davide", "surname":"carboni", "age":35, "email":"davide@foo.bar"}
user3={"name":"stefano", "surname":"sanna", "age":32, "email":"stefano@foo.bar"}
users=[user1,user2,user3]
class Root(resource.Resource):
isLeaf=False
def render_GET(self, request):
return "Arkanoid?"
class ListUsers(resource.Resource):
isLeaf=True
def render_GET(self, request):
userList=[us['name'] for us in users]
return str(userList)
class User(resource.Resource):
isLeaf=True
def render_GET(self, request):
name=request.args['name'][0]
record=filter(lambda(x): name==x['name'], users)[0]
return str(record)
def render_POST(self,request):
record=eval(request.content.read())
#WARNING. USING EVAL ON USER TRANSMITTED DATA
#IS A SEVERE SECURITY FLAW.
#USE A PARSER LIKE SIMPLEJSON INSTEAD
users.append(record)
return 'http://localhost/user?name=%s' % (record['name'])
def render_PUT(self,request):
name=request.args['name'][0]
newrecord=eval(request.content.read())
#WARNING. USING EVAL ON USER TRANSMITTED DATA
#IS A SEVERE SECURITY FLAW.
#USE A PARSER LIKE SIMPLEJSON INSTEAD
oldrecord=filter(lambda(x): name==x['name'], users)[0]
for key in oldrecord:
oldrecord[key]=newrecord[key]
return "OK"
def render_DELETE(self,request):
name=request.args['name'][0]
record=filter(lambda(x): name==x['name'], users)[0]
users.remove(record)
return "OK"
if __name__ == "__main__":
root=Root()
root.putChild("user",User())
root.putChild("listUsers",ListUsers())
root.putChild("d",File("."))
site = server.Site(root)
reactor.listenTCP(8000, site)
reactor.run()