Come ottenere POST JSON in Flask?


326

Sto cercando di creare una semplice API usando Flask, in cui ora voglio leggere alcuni JSON POSTATI. Faccio il POST con l'estensione Postman per Chrome, e il POST JSON I è semplicemente {"text":"lalala"}. Provo a leggere il JSON usando il seguente metodo:

@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
    content = request.json
    print content
    return uuid

Sul browser restituisce correttamente l'UUID che ho inserito nel GET, ma sulla console, viene semplicemente stampato None(dove mi aspetto che stampi {"text":"lalala"}. Qualcuno sa come posso ottenere il JSON pubblicato all'interno del metodo Flask?

Risposte:


428

Prima di tutto, l' .jsonattributo è una proprietà che delega al request.get_json()metodo , che documenta il motivo per cui vedi Nonequi.

È necessario impostare il tipo di contenuto della richiesta su application/jsonaffinché la .jsonproprietà e il .get_json()metodo (senza argomenti) funzionino poiché entrambi genereranno Nonediversamente. Vedi la documentazione di FlaskRequest :

Questo conterrà i dati JSON analizzati se il mimetype indica JSON ( application / json , vedi is_json()), altrimenti lo sarà None.

Puoi dire request.get_json()di saltare il requisito del tipo di contenuto passandogli l' force=Trueargomento della parola chiave.

Si noti che se un a questo punto viene sollevata un'eccezione (che potrebbe comportare una risposta di 400 richieste errate), i dati JSON non sono validi. È in qualche modo malformato; potresti volerlo controllare con un validatore JSON.


Ho pensato che quando a questo punto viene sollevata un'eccezione, è più probabile che si traduca in una risposta di errore interno 500, non è vero?
iBug

101

Per riferimento, ecco il codice completo per come inviare json da un client Python:

import requests
res = requests.post('http://localhost:5000/api/add_message/1234', json={"mytext":"lalala"})
if res.ok:
    print res.json()

L'ingresso "json =" imposterà automaticamente il tipo di contenuto, come discusso qui: Pubblica JSON usando le richieste Python

E il client sopra funzionerà con questo codice lato server:

from flask import Flask, request, jsonify
app = Flask(__name__)

@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
    content = request.json
    print content['mytext']
    return jsonify({"uuid":uuid})

if __name__ == '__main__':
    app.run(host= '0.0.0.0',debug=True)

71

Questo è il modo in cui lo farei e dovrebbe essere

@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
    content = request.get_json(silent=True)
    # print(content) # Do your processing
    return uuid

Con silent=Trueset, la get_jsonfunzione fallirà silenziosamente quando si tenta di recuperare il corpo json. Per impostazione predefinita, questo è impostato su False. Se ti aspetti sempre un corpo json (non facoltativo), lascialo come silent=False.

L'impostazione force=Trueignorerà il request.headers.get('Content-Type') == 'application/json'controllo che il pallone fa per te. Per impostazione predefinita, anche questo è impostato su False.

Vedi la documentazione del pallone .

Consiglio vivamente di partire force=Falsee di fare in modo che il client invii l' Content-Typeintestazione per renderlo più esplicito.

Spero che questo ti aiuti!


2
Dipende se il corpo json è facoltativo o meno, quindi dipende dal tuo caso
radtek,

2
Non vedo alcun caso in cui avrebbe senso pubblicare a volte un json valido e altre volte un json non valido. Sembra due diversi punti finali
vidstige,

1
Come ho detto, se un endpoint accetta un corpo json "opzionale", è possibile utilizzare silent=True. Sì, questo è possibile e lo uso. È davvero basato su come si progetta la tua API da consumare. Se non esiste un caso simile per l'endpoint, rimuoverlo silent=Trueo impostarlo in modo esplicito su False.
Radtek,

Per chiarezza, il print(content)dopo content = request.get_json()stampa l'oggetto ... ma come un oggetto Python valido (e non come un oggetto JSON valido). Ad esempio, utilizza virgolette singole mentre JSON richiede rigorosamente virgolette doppie per entrambi i valori chiave (stringhe) come valori stringa. Se si desidera la rappresentazione JSON, utilizzare json.dumps()con l'oggetto.
Jochem Schulenklopper,

24

Supponendo che tu abbia pubblicato JSON valido con il application/jsontipo di contenuto, request.jsoni dati JSON verranno analizzati.

from flask import Flask, request, jsonify

app = Flask(__name__)


@app.route('/echo', methods=['POST'])
def hello():
   return jsonify(request.json)

3
Per aggiungere a questa risposta potrebbe essere la richiesta che è possibile inviare a questo endpoint response = request.post('http://127.0.0.1:5000/hello', json={"foo": "bar"}). A seguito di questa corsa response.json()dovrebbe tornare{'foo': 'bar'}
ScottMcC

Si potrebbe notare che {'foo': 'bar'}JSON non è valido però. Potrebbe essere una rappresentazione di oggetti Python valida che assomiglia molto a JSON, ma JSON valida utilizza rigorosamente virgolette doppie.
Jochem Schulenklopper,

@JochemSchulenklopper il get_json()metodo di richiesta decodifica da oggetti JSON a Python, sì. Dove ti aspetti che produca un documento JSON valido?
Martijn Pieters

@MartijnPieters, stavo solo facendo una dichiarazione su una peculiarità che mi ha morso almeno due volte :-) Ma sì, normalmente mi aspetto una funzione chiamata .json()o .get_json()che restituisca una rappresentazione di oggetto JSON valida, non un dict Python. Sto solo guardando il nome e deduco cosa potrebbe venirne fuori.
Jochem Schulenklopper

6

Per tutti coloro il cui problema era dovuto alla chiamata ajax, ecco un esempio completo:

Chiamata Ajax: la chiave qui è usare un dicte poiJSON.stringify

    var dict = {username : "username" , password:"password"};

    $.ajax({
        type: "POST", 
        url: "http://127.0.0.1:5000/", //localhost Flask
        data : JSON.stringify(dict),
        contentType: "application/json",
    });

E sul lato server:

from flask import Flask
from flask import request
import json

app = Flask(__name__)

@app.route("/",  methods = ['POST'])
def hello():
    print(request.get_json())
    return json.dumps({'success':True}), 200, {'ContentType':'application/json'} 

if __name__ == "__main__":
    app.run()

1
Questa è la cosa che ha funzionato per me, grazie mille! :)
vjjj

1

Per dare un altro approccio.

from flask import Flask, jsonify, request
app = Flask(__name__)

@app.route('/service', methods=['POST'])
def service():
    data = json.loads(request.data)
    text = data.get("text",None)
    if text is None:
        return jsonify({"message":"text not found"})
    else:
        return jsonify(data)

if __name__ == '__main__':
    app.run(host= '0.0.0.0',debug=True)

0

Supponendo che tu abbia pubblicato JSON valido,

@app.route('/api/add_message/<uuid>', methods=['GET', 'POST'])
def add_message(uuid):
    content = request.json
    print content['uuid']
    # Return data as JSON
    return jsonify(content)

0

Prova a usare il parametro force ...

request.get_json(force = True)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.