Python: FastAPI-Fehler 422 mit POST-Anfrage beim Senden von JSON-Daten
Lesezeit: 6 Minuten
Schmied
Ich baue eine einfache API zum Testen einer Datenbank. Wenn ich es benutze GET Anfrage funktioniert alles gut, aber wenn ich auf wechsle POSTIch bekomme 422 Unprocessable Entity Fehler.
Hier ist der FastAPI-Code:
from fastapi import FastAPI
app = FastAPI()
@app.post("/")
def main(user):
return user
Dann meine Anfrage mit JavaScript
let axios = require('axios')
data = {
user: 'smith'
}
axios.post('http://localhost:8000', data)
.then(response => (console.log(response.url)))
Wenn der Parameter auch im deklariert ist Wegwird es als Pfadparameter verwendet.
Wenn der Parameter von a ist singulärer Typ (wie int, float, str, bool usw.) wird als a interpretiert Anfrage Parameter.
Wenn der Parameter als Typ a deklariert ist Pydantisches Modellwird es als Anfrage interpretiert Körper.”
Um also einen POST-Endpunkt zu erstellen, der einen Textkörper mit einem Benutzerfeld empfängt, würden Sie etwa Folgendes tun:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Data(BaseModel):
user: str
@app.post("https://stackoverflow.com/")
def main(data: Data):
return data
In meinem Fall habe ich die Python-API aus einem anderen Python-Projekt wie diesem aufgerufen
queryResponse = requests.post(URL, data= query)
Ich habe die Dateneigenschaft verwendet, sie in JSON geändert, dann hat es bei mir funktioniert
queryResponse = requests.post(URL, json = query)
Danke! Damit hat meine Funktion auch funktioniert … aber ich wünschte immer noch, ich wüsste, warum die Übergabe eines Diktats über Daten (wie in der Hilfedatei beschrieben) den Fehlerstatuscode 422 verursacht.
– Mark Seagoe
11. November 2021 um 0:59
Ich habe gelesen, dass das Datenfeld für das FormData-Format gedacht ist … das eine Javascript-Klasse zur Übergabe von HTML-Formulardaten zu sein scheint. github.com/tiangolo/fastapi/issues/3373
– Mark Seagoe
11. November 2021 um 3:03
Wow, die nicht verarbeitbare Entität 422 ist schließlich ein Datenformatierungsproblem. Der Fehlercode und die Fehlermeldung sind nicht explizit.
– Alsushi
16. März 2022 um 10:35 Uhr
Chris
Eine Antwort mit Statuscode 422 (unprocessable entity) verfügt über einen Antworttext, der die Fehlermeldung angibt und genau angibt, welcher Teil Ihrer Anfrage fehlt oder nicht dem erwarteten Format entspricht. Der von Ihnen bereitgestellte Codeausschnitt zeigt, dass Sie etwas posten möchten JSON Daten an einen Endpunkt, der sie erwartet user sein query Parameter, statt JSON Nutzlast. Daher die 422 unprocessable entity Fehler. Unten sind angegeben vier verschiedene Optionen wie man einen zu erwartenden Endpunkt definiert JSON Daten.
Option 1
Gemäß der Dokumentationwenn Sie senden müssen JSON Wenn Sie Daten von einem Client (z. B. einem Browser) an Ihre API senden, senden Sie sie als Anfragetext (durch ein POST Anfrage). Um einen Anfragetext zu deklarieren, können Sie verwenden Pydantisch Modelle.
from pydantic import BaseModel
class User(BaseModel):
user: str
@app.post("https://stackoverflow.com/")
def main(user: User):
return user
Option 2
Wenn man keine Pydantic-Modelle verwenden möchte, könnte man sie auch verwenden Körper Parameter. Wenn ein einzelner Körperparameter verwendet wird (wie in Ihrem Beispiel), können Sie den speziellen verwenden Körper Parameter einbetten.
from fastapi import Body
@app.post("https://stackoverflow.com/")
def main(user: str = Body(..., embed=True)):
return {'user': user}
Option 3
Eine andere (weniger empfohlene) Möglichkeit wäre die Verwendung von a Dict Typ (oder einfach dict in Python 3.9+), um a zu deklarieren key:value Paar. Auf diese Weise können Sie jedoch keine benutzerdefinierten Validierungen für verschiedene Attribute wie erwartet verwenden JSONwie Sie es mit Pydantic-Modellen tun würden oder Body Felder (z. B. prüfen, ob eine E-Mail-Adresse gültig ist oder ob eine Zeichenfolge einem bestimmten Muster folgt).
from typing import Dict, Any
@app.post("https://stackoverflow.com/")
def main(payload: Dict[Any, Any]): # or, payload: dict[Any, Any]
return payload
Option 4
Wenn Sie sicher sind, dass die eingehenden Daten gültig sind JSONkönnen Sie verwenden Starlettes Request direkt widersprechen um den Anfragetext als zu analysieren JSONverwenden await request.json(). Allerdings können Sie bei diesem Ansatz nicht nur keine benutzerdefinierten Validierungen für Ihre Attribute verwenden, sondern Sie müssten auch Ihren Endpunkt mit definieren async defseit request.json() ist ein async Methode und daher muss man await es (schauen Sie sich an diese Antwort Weitere Informationen zu def vs async def).
Wenn Sie möchten, können Sie auch einige Überprüfungen vornehmen Content-Type Fordern Sie den Header-Wert an, bevor Sie versuchen, die Daten zu analysieren, ähnlich wie bei dieser Antwort. Allerdings nur, weil eine Anfrage besagt application/json im Content-Type Header bedeutet dies nicht immer, dass dies wahr ist oder dass die eingehenden Daten gültig sind JSON (z. B. fehlt möglicherweise eine geschweifte Klammer, ein Schlüssel hat keinen Wert usw.). Daher könnten Sie a verwenden try-except blockieren, wenn Sie versuchen, die Daten zu analysieren, damit Sie alle Daten verarbeiten können JSONDecodeErrorfalls es ein Problem mit der Art und Weise gibt, in der Sie JSON Daten werden formatiert.
Entsprechende Antworten finden Sie hier und auch hier. Für Beispiele mit axiosBitte schauen Sie sich diese Antwort sowie diese Antwort und diese Antwort an.
Chris, dein Vorschlag zu „Payload“ hat mir geholfen. Vielen Dank
– Iker
26. April um 18:59 Uhr
Alan
Wenn Sie das verwenden fetch API und bekomme immer noch die 422 Nicht verarbeitbare Entitätstellen Sie sicher, dass Sie das eingestellt haben Inhaltstyp Header:
Dies hat das Problem in meinem Fall gelöst. Auf der Serverseite verwende ich Pydantic-Modelle. Wenn Sie diese also nicht verwenden, lesen Sie die obigen Antworten.
Yagiz Degirmenci
FastAPI basiert auf Hinweise zum Python-Typ Wenn Sie also einen Abfrageparameter übergeben, wird dieser akzeptiert Taste:Wert Paar müssen Sie es irgendwie deklarieren.
Sogar so etwas wird funktionieren
from typing import Dict, Any
...
@app.post("/")
def main(user: Dict[Any, Any] = None):
return user
Out: {"user":"Smith"}
Aber die Verwendung von Pydantic ist viel effektiver
class User(BaseModel):
user: str
@app.post("/")
def main(user: User):
return user
Out: {"user":"Smith"}
Avinash Ravi
Bei POST-Anfragen zur Aufnahme des Anfragetextes müssen Sie wie folgt vorgehen
Erstellen Sie einen Pydantic-Basismodellbenutzer
from pydantic import BaseModel
class User(BaseModel):
user_name: str
@app.post("https://stackoverflow.com/")
def main(user: User):
return user
Yong
In meinem Fall erwartet mein FastAPI-Endpunkt Formulardaten anstelle von JSON. Daher besteht die Lösung darin, Formulardaten anstelle von JSON zu senden. (Hinweis: Für Node-JS ist FormData nicht verfügbar und Formulardaten kann verwendet werden)
14533300cookie-checkPython: FastAPI-Fehler 422 mit POST-Anfrage beim Senden von JSON-Datenyes
Haben Sie den Server (wie uvicorn) gestartet, auf dem die Fastapi-Anwendung läuft?
– Orkun Kocyigit
27. Januar 2020 um 10:37 Uhr