Cómo leer el parámetro URL y el cuerpo escribiendo en Fast API Python

Quiero crear una definición genérica de endpoint en Fast API Python que lea el parámetro URL path y luego llama un método específico para hacer una derealización. Pero siempre consigo

422 Unprocessable Entity

Así que espero que funcione así:

/answer/aaaa - confianza handle_generic_answer - confianza read_item_aaa, type body to ModelAAA

/answer/bbb - confianza handle_generic_answer - confianza read_item_bbb, type body to ModelBBB etc.

Aquí está el código de endpoint genérico:

@app.post("/answer/{type}")
def handle_generic_answer(type: str, item):
# I also tried 
# def handle_generic_answer(type: str, item: Any):
# or
# def handle_generic_answer(type: str, item: Optional):
    switcher = {
        'aaaa': read_item_aaa,
        'bbb': read_item_bbb,
        'nothing': unrecognised_answer
    }
    func = switcher.get(type, unrecognised_answer)
    print('answer >> ' + type)
    func(item)

entonces tengo métodos separados llamados basados en un type valor:

def read_item_aaa(item: ModelAAA):
    update_aaa(item)
    return {"type": "aaa", "result": "success"}

def read_item_bbb(item: ModelBBB):
    update_bbb(item)
    return {"type": "bbb", "result": "success"}

y un defecto -

def unrecognised_answer(type):
    print("unrecognised_answer")
    raise HTTPException(status_code=400, detail="answer type not found")
    return {}

modelos se definen así:

from pydantic import BaseModel, Field

class ModelAAA(BaseModel):
    field1: str
    field2: list = []
    

Pero si llamo

http://localhost:8000/answer/aaa

o http://localhost:8000/answer/some-other-url

Siempre tengo 422:

{
    "detail": [
        {
            "loc": [
                "query",
                "item"
            ],
            "msg": "field required",
            "type": "value_error.missing"
        }
    ]
}

Pregunta hecha hace 3 años, 4 meses, 29 días - Por binarybard1cc8


3 Respuestas:

  • Olvidaste anotar el parámetro corporal item.

    Sin esto item se trata como consulta str Parámetro. Por ejemplo:

    @app.post("/answer/{type}")
    def handle_generic_answer(type: str, item: Union[ModelAAA, ModelBBB]):
    

    Respondida el Dec 17, 2020 a las 22:08 - por pythonpirate

    Votos positivos: 0 | Votos negativos: 0

  • El error que estás experimentando se debe a que el endpoint genérico que has creado espera un parámetro adicional en la solicitud POST llamado "item", pero en realidad no estás enviando ningún dato en el cuerpo de la solicitud.

    Para poder leer tanto el parámetro URL como el cuerpo de la solicitud en FastAPI, puedes utilizar Pydantic para definir un modelo que represente el cuerpo de la solicitud y especificarlo como un parámetro en tu función de manejo genérico.

    Aquí te muestro cómo puedes modificar tu código para lograr esto:

    python
    from typing import Any
    from fastapi import FastAPI, HTTPException
    from pydantic import BaseModel
    
    app = FastAPI()
    
    

    Define el modelo para el cuerpo de la solicitud

    class GenericItem(BaseModel): field1: str field2: list = []

    Endpoint genérico que recibe el tipo y el cuerpo en la solicitud

    @app.post("/answer/{type}") def handle_generic_answer(type: str, item: GenericItem): switcher = { 'aaaa': read_item_aaa, 'bbb': read_item_bbb, 'nothing': unrecognised_answer } func = switcher.get(type, unrecognised_answer) print('answer >> ' + type) func(item)

    Métodos para manejar diferentes tipos de elementos

    def read_item_aaa(item: GenericItem): update_aaa(item) return {"type": "aaa", "result": "success"} def read_item_bbb(item: GenericItem): update_bbb(item) return {"type": "bbb", "result": "success"} def unrecognised_answer(type): print("unrecognised_answer") raise HTTPException(status_code=400, detail="answer type not found") return {}

    Modelos se definen así:

    class ModelAAA(BaseModel): field1: str field2: list = [] class ModelBBB(BaseModel): field1: str field2: list = []

    Puedes añadir más modelos según sea necesario

    Métodos de actualización específicos

    def update_aaa(item: ModelAAA):

    Implementa la lógica para actualizar ModelAAA

    pass def update_bbb(item: ModelBBB):

    Implementa la lógica para actualizar ModelBBB

    pass

    Con esta modificación, ahora tu endpoint genérico espera recibir un objeto JSON en el cuerpo de la solicitud que coincida con el modelo GenericItem. Asegúrate de enviar los datos requeridos en el cuerpo de tu solicitud POST cuando pruebes tus endpoints.

    Respondida el Dec 18, 2020 a las 22:09 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • El error 422 Unprocessable Entity indica que la solicitud tiene un formato válido, pero no se puede procesar debido a un error en el cuerpo de la solicitud. En este caso, el problema es que FastAPI espera que el cuerpo de la solicitud coincida con el tipo de ModelAAA, pero estás enviando un cuerpo vacío.

    Para resolver este problema, puedes hacer que el parámetro item sea opcional y proporcionar un valor predeterminado. Aquí tienes un código actualizado:

    python
    @app.post("/answer/{type}")
    def handle_generic_answer(type: str, item: ModelAAA = None):
        ...
    

    Al hacer que item sea opcional, FastAPI ya no esperará un cuerpo de solicitud. Si se proporciona un cuerpo de solicitud, FastAPI lo analizará y lo convertirá en una instancia de ModelAAA. Si no se proporciona un cuerpo de solicitud, item será None.

    Espero que esto resuelva tu problema. Déjame saber si tienes más preguntas.

    Respondida el Dec 18, 2020 a las 22:20 - por Gemini

    Votos positivos: 0 | Votos negativos: 0