Type aangevraagde zoekopdracht in Tornado

Hoe vertel je in Tornado de verschillende soorten aanvragen? En wat is de juiste manier om de verzoeken op te splitsen? Als ik uiteindelijk naar /item/1.xml ga, wil ik dat xml, /item/1.html een goede HTML-weergave is, enzovoort.

Zoiets als:

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

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

of

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

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

0

3 antwoord

Ik geef de voorkeur aan een URL die zichzelf beschrijft als een REST-app. Een URL-onderdeel hoeft niet nodig te zijn om het formaat van de resource weer te geven. http://www.enterprise.com/customer/abc/order/123 moet de resource vertegenwoordigen, ongeacht of het xml/html/json is. Een manier om het gevraagde formaat te verzenden, is door het als een van de verzoekparameters te verzenden.

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

Gebruik de parameter request om te serialiseren naar het juiste formaat.

2
toegevoegd
Bewerkte post met hetzelfde, maar ik ging echt voor een gebruikersgerichte implementatie van een RESTful api zoals die te zien is in rails
toegevoegd de auteur odgrim, de bron

Stel eerst de handlers in om te rekenen op een rustgevende stijl-URI. We gebruiken 2 stukjes regex op zoek naar een ID en een mogelijk verzoekformaat (bijv. Html, xml, json enz.)

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)

Nu, definieer in de handler een herbruikbare functie parseRestArgs (ik heb de mijne in een BaseHandler geplaatst maar hier geplakt voor het gemak van begrip/om ruimte te besparen) die id's en aanvraagformaten splitst. Omdat je id's in een bepaalde volgorde zou moeten verwachten, plak ik ze in een lijst.

De get-functie kan meer worden geabstraheerd, maar toont het basisidee van het splitsen van uw logica in verschillende aanvraagindelingen ...

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...
1
toegevoegd

mimetype is de juiste manier om dit te doen, maar ik kan zien waar een eindgebruiker een meer simplistische manier wil om toegang te krijgen tot de gegevens in het formaat dat zij wensen.

Om compatibiliteit met bibliotheken die aan de standaarden voldoen te behouden, moet u uiteindelijk het antwoordtype bepalen op basis van het aangevraagde mimetype en reageren met het juiste mimetype in de headers.

Een manier om dit te bereiken zonder iets te breken, is om een ​​parser toe te voegen die de URI controleert die is aangevraagd voor een achtervoegsel dat overeenkomt met een tuple van gedefinieerde achtervoegsels waarop de route kan reageren, als dit wel het geval is en het mimetype nog niet is opgegeven het mimetype dat is doorgegeven om het juiste type voor het achtervoegsel te zijn.

Zorg ervoor dat de uiteindelijke beslissing gebaseerd is op het geleverde mimetype en niet het achtervoegsel.

Op deze manier kunnen anderen communiceren met uw RESTful-service op de manier zoals ze gewend zijn en kunt u nog steeds gebruiksgemak voor mensen enz. Behouden.

~ bewerk ~

Dit is een voorbeeld van een regexp die controleert of het eindigt op .js | .html | .xml | .json. Dit gaat ervan uit dat je de volledige URI hebt gekregen.

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

Hier is een voorbeeld dat gemakkelijker te interpreteren is maar minder robuust

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

These regex's are taken from rfc2396

1
toegevoegd