Frage

In Tornado, how do you tell apart the different request types? Also, what is the proper way to split out the requests? In the end if I go to /item/1.xml, I want xml, /item/1.html to be a proper html view etc.

Something like:

def getXML():
    return self.render('somexmlresult.xml')

def getHTML():
    return self.rendeR('htmlresult.html')

or

def get():
    if request == 'xml':
        return self.render('somexmlresult.xml')
    elif request == 'html':
        return self.render('htmlresult.html')

~ edit ~ I was shooting for something along the lines of rails' implementation seen here

War es hilfreich?

Lösung 3

First, set up the handlers to count on a restful style URI. We use 2 chunks of regex looking for an ID and a potential request format (ie html, xml, json etc)

class TaskServer(tornado.web.Application):
    def __init__(self, newHandlers = [], debug = None):
        request_format = "(\.[a-zA-Z]+$)?"
        baseHandlers = [
            (r"/jobs" + request_format, JobsHandler),
            (r"/jobs/", JobsHandler),
            (r"/jobs/new" + request_format, NewJobsHandler),
            (r"/jobs/([0-9]+)/edit" + request_format, EditJobsHandler)
        ]
        for handler in newHandlers:
            baseHandlers.append(handler)


    tornado.web.Application.__init__(self, baseHandlers, debug = debug)

Now, in the handler define a reusable function parseRestArgs (I put mine in a BaseHandler but pasted it here for ease of understanding/to save space) that splits out ID's and request formats. Since you should be expecting id's in a particular order, I stick them in a list.

The get function can be abstracted more but it shows the basic idea of splitting out your logic into different request formats...

class JobsHandler(BaseHandler):
    def parseRestArgs(self, args):
        idList = []
        extension = None
        if len(args) and not args[0] is None:
            for arg in range(len(args)):
                match = re.match("[0-9]+", args[arg])
                if match:
                    slave_id = int(match.groups()[0])

            match = re.match("(\.[a-zA-Z]+$)", args[-1])
            if match:
                extension = match.groups()[0][1:]

        return idList, extension

    def get(self, *args):
        ### Read
        job_id, extension = self.parseRestArgs(args)

        if len(job_id):
            if extension == None or "html":
               #self.render(html) # Show with some ID voodoo
               pass
            elif extension == 'json':
                #self.render(json) # Show with some ID voodoo
                pass
            else:
                raise tornado.web.HTTPError(404) #We don't do that sort of thing here...
        else:
            if extension == None or "html":
                pass
                # self.render(html) # Index- No ID given, show an index
            elif extension == "json":
                pass
                # self.render(json) # Index- No ID given, show an index
            else:
                raise tornado.web.HTTPError(404) #We don't do that sort of thing here...

Andere Tipps

I would prefer a self describing url like a RESTful application. An url part need not be required to represent the format of the resource. http://www.enterprise.com/customer/abc/order/123 must represent the resource irrespective of whether it is xml/html/json. A way to send the requested format is to send it as one of the request parameters.

http://www.enterprise.com/customer/abc/order/123?mimetype=application/xml
http://www.enterprise.com/customer/abc/order/123?mimetype=application/json
http://www.enterprise.com/customer/abc/order/123?mimetype=text/html

Use the request parameter to serialize to the appropriate format.

mimetype is the correct way to do this, however I can see where an end user would want a more simplistic way of accessing the data in the format they wish.

In order to maintain compatibility with standards compliant libraries etc you should ultimately determine the response type based on the mimetype requested and respond with the appropriate mimetype in the headers.

A way to achieve this while not breaking anything would be to add a parser that checks the URI that was requested for a suffix that matches a tuple of defined suffixes that the route can respond to, if it does and the mimetype is not already specified change the mimetype passed in to be the correct type for the suffix.

Make sure that the final decision is based on the supplied mimetype not the suffix.

This way others can interact with your RESTful service in the way their used to and you can still maintain ease of use for humans etc.

~ edit ~

Heres an example regexp that checks to see if it ends in .js | .html | .xml | .json. This is assuming your given the full URI.

(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*\.(?:js|html|xml|json))(?:\?([^#]*))?(?:#(.*))?

Here's an example that's easier to interpret but less robust

^https?://(?:[a-z\-]+\.)+[a-z]{2,6}(?:/[^/#?]+)+\.(?:js|html|xml|json)$

These regex's are taken from rfc2396

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top