2013-07-18 30 views
10

Çeşitli istek yöntemlerinin (GET, url x-www-form-urlencoded POST ve json POST) için bir API maruz çalışıyorum:Tek bir görünüm yönteminde birden çok istek türünü kabul etmenin daha iyi bir yolu var mı?

@app.route('/create', methods=['GET', 'POST']) 
def create_file(): 
    if request.method == 'GET': 
     n = request.args.get('n') 
     t = request.args.get('t') 
    if request.method == 'POST': 
     if request.json: 
      n = request.json['n'] 
      t = request.json['t'] 
     else: 
      n = request.form['n'] 
      t = request.form['t'] 
    try: 
     n = int(n) 
    except: 
     n = 1 
    ... 

yukarıda da ayrıntılı görünür. Bunu yazmanın daha basit veya daha iyi bir yolu var mı? Teşekkürler.

@app.route('/create', methods=['GET', 'POST']) 
def create_file(): 
    params = None 
    if request.method == 'GET': 
     params = request.args 
    if request.method == 'POST': 
     if request.json: 
      params = request.json 
     else: 
      params = request.form 

    n = params.get('n') 
    t = params.get('t') 

    try: 
     n = int(n) 
    except: 
     n = 1 
    ... 
+2

Genellikle API yöntemlerimi web yöntemlerimden ayrı bir plana taşıyorum. Bu şekilde işlevler birbirini karıştırmaz ve daha kolay bakım sağlar. Aynı zamanda [flask-RESTful] 'a da bakıyorum (http://flask-restful.readthedocs.org/en/latest/) – sean

+0

Planlara daha fazla bakmak gerekecek. Şimdilik, Miguel'in cevabını seçtim. Teşekkürler. – iandexter

cevap

14

bu daha iyi görünüyor mu:

+0

Evet, tercih ettiğim şey bu. Teşekkürler. – iandexter

4

Orada hiçbir şey içine kod tekrar durduruluyor? JSON POST isteğini farklı bir rotaya taşımayı kabul ederseniz (ki gerçekten de bunu yapmanız gerekir) benim görüşüme göre biraz daha temiz. Başkaları tarafından önerildiği gibi

def _create_file(n, t): 
    try: 
     n = int(n) 
    except: 
     n = 1 
    ... 

@app.route('/create') 
def create_file(): 
    n = request.args.get('n') 
    t = request.args.get('t') 
    return _create_file(n, t) 

@app.route('/create', methods = ['POST']) 
def create_file_form(): 
    n = request.form.get('n') 
    t = request.form.get('t') 
    return _create_file(n, t) 

@app.route('/api/create', methods = ['POST']) 
def create_file_json(): 
    if not request.json: 
     abort(400); # bad request 
    n = request.json.get('n') 
    t = request.json.get('t') 
    return _create_file(n, t) 
+0

Gerçekten çok daha iyi değil. [İçerik müzakeresi] (https://en.wikipedia.org/wiki/Content_negotiation) Flask (IMHO) ile kolayca yapılmayan bir şey değildir. Varsayılan olarak istekleri sadece URL ve yöntemle gönderilir.Başlık değerine göre ne kadar çalışacağını bilmiyorum. – dAnjou

+0

O zaman siz defenetly [flask-RESTful] (http://flask-restful.readthedocs.org/en/latest/) – twil

+1

'a bakmalısınız. Bunu kesinlikle yapmayacağım. 150LoC'den daha az olan https://github.com/nickstenning/negotiate kullanmayı tercih ediyorum. – dAnjou

0

kullanın Flask-Restful uzantısı. Daha sonra sadece böyle bir şey yapabilirsiniz: ... vb

class CreateFile(Resource): 
    def get(self): 
     args = parser.parse_args() 
     n,t = args['n'], args['t'] 

    def post(self, todo_id): 
     # do post stuff 

ve

+0

İçerik müzakeresi söz konusu olduğunda işler nasıl kısalıyor? – dAnjou

+0

Bu sadece bir öneridir. OP, “daha ​​basit ya da daha iyi bir yol” istiyor ve mutlaka daha kısa değil. – codegeek

+0

Peki, o zaman "daha kısa" ile "daha basit veya daha iyi" değiştirin. – dAnjou

0

o zaten bir cevap kabul ettik çünkü aradığınız buysa bilmiyorum ama sen yapabilirsin standart refaksiyon teknikleri uygulayarak bir çok ayrıntıyı kaldırın. İlk olarak, her bir işlev için tek bir sorumluluk:

@app.route('/create', methods=['GET', 'POST']) 
def create_file(): 
    n, t = get_nt_request_data() 
    return process_n(n) 

def get_nt_request_data(): 
    if request.method == 'GET': 
     return get_nt_query_params() 
    if request.method == 'POST': 
     if request.json: 
      return get_nt_json() 
     else: 
      return get_nt_form() 
    return n, t 

def get_nt_query_params(): 
    n = request.args.get('n') 
    t = request.args.get('t') 
    return n, t 

def get_nt_json(): 
    n = request.json['n'] 
    t = request.json['t'] 
    return n, t 

def get_nt_form(): 
    n = request.form['n'] 
    t = request.form['t'] 
    return n, t 

def process_n(n): 
    try: 
     n = int(n) 
    except: 
     n = 1 

Şimdi, bu kesinlikle daha kısa, ama ben şahsen çok net olduğunu düşünüyorum. Her bir işlevin açıkça tanımlanmış bir amacı vardır ve dağınık değildir. Şahsen iki alanlı bir nesneye "n, t" yapardım, ama tamamen size kalmış ve uygulamanız için ne işe yarıyor. 2. Adım: Orada oldukça belirgin bir kopya/yapıştırmamız var. Hadi temizleyelim.

@app.route('/create', methods=['GET', 'POST']) 
def create_file(): 
    n, t = get_nt_request_data() 
    return process_n(n) 

def get_nt_request_data(): 
    if request.method == 'GET': 
     return get_nt_query_params() 
    if request.method == 'POST': 
     if request.json: 
      return get_nt_json() 
     else: 
      return get_nt_form() 
    return n, t 

def get_nt_query_params(): 
    return build_nt(request.args) 

def get_nt_json(): 
    return build_nt(request.json) 

def get_nt_form(): 
    return build_nt(request.form) 

def build_nt(resource): 
    return resource.get("n"), resource.get("t") 

def process_n(n): 
    try: 
     n = int(n) 
    except: 
     n = 1 

Şimdi bir yere alıyorsanız! Fakat bunu 20 farklı kaynak için yaparsak (farklı son noktalarınızın HTTP fiilleri için benzer kurallar izlediğini varsayarak), temelde aynı şeyi yapan bir dizi get_xx_request_data işlevine sahip olacağız. Parametrelendirelim!

@app.route('/create', methods=['GET', 'POST']) 
def create_file(): 
    n, t = get_request_data(build_nt) 
    return process_n(n) 

def build_nt(resource): 
    return resource.get("n"), resource.get("t") 

def process_n(n): 
    try: 
     n = int(n) 
    except: 
     n = 1 

# in a shared module somewhere 
def get_request_data(builder): 
    if request.method == 'GET': 
     return builder(request.args) 
    if request.method == 'POST': 
     if request.json: 
      return builder(request.json) 
     else: 
      return builder(request.form) 
    return n, t 

Bitiş noktası için yalnızca 11 satır kod ve diğer kullanıcılar için yeniden kullanabileceğiniz paylaşılan bir işlev. (Bu, mevcut çerçevelerin ne yaptıklarına kavramsal olarak benzediğini varsayıyorum; bunları kontrol etme şansım olmadı.)

Son bir not: GET isteğiyle bir dosya oluşturmak size biraz istemciler üzerinde ne kadar kontrole sahip olduğunuza ve proxy'lere müdahale ettiğinize bağlı olarak kaşların ve muhtemelen bazı tuhaf böceklerin. Bir GET'in idempotent olması gerekiyordu, bu yüzden istemcilerin sunucudaki herhangi bir durum değişikliğini beklemeden tüm willy-nilly'leri yeniden denemeleri gerekiyordu (ve bir şey oluşturmak kesinlikle bir durum değişikliğidir). Teoride, bir vekil, bir ağ hıçkırışından sonra bir GET komutunu, orijinal müşteriye iki kere denediğini bile söylemeden tekrarlayabiliyordu, ama pratikte bu hiç bir zaman bana sorun çıkarmadı.

İlgili konular