luolingchun / flask-openapi3

Generate REST API and OpenAPI documentation for your Flask project.
https://luolingchun.github.io/flask-openapi3/
MIT License
189 stars 29 forks source link

Parsing list of objects from API fails #185

Open Ph0tonic opened 1 day ago

Ph0tonic commented 1 day ago

Environment:

Hello, I have tried to search for any related issue but haven't been able to found one. I have a form which provides a list of objects as entry to my API: image

However when I try to parse using OpenAPI endpoint:

class Signature(BaseModel):
    date: str = ""
    name: str = ""
    fonction: str = ""

class Options(BaseModel):
    signatures: List[Signature]
    header: bool = True

# some code to create app

@app.post("/generate")
def generate(form: Options) -> any:
    # some code

I get the following error:

[
  {
    "type": "missing",
    "loc": [
      "signatures"
    ],
    "msg": "Field required",
    "input": {
      "header": "true"
    },
    "url": "https://errors.pydantic.dev/2.9/v/missing"
  }
]

My guess is that the bug is linked with the way flask-openapi3 parses data and provides it to pydantik but I am not sure where. Maybe I am just using the wrong way but I haven't found any documentation of this. Any help is welcome.

luolingchun commented 1 day ago

You passed the wrong parameter, it's not signatures[], it's' signatures

curl -X 'POST' \
  'http://127.0.0.1:5000/book' \
  -H 'accept: */*' \
  -H 'Content-Type: multipart/form-data' \
  -F 'header=true' \
  -F 'signatures={"date":"","function":"","name":""}' \
  -F 'signatures={"date": "","function": "","name": ""}' \
  -F 'signatures={"date": "","function": "","name": ""}'

If it is not for file upload, it is recommended to use body instead of form.

By the way, if you want use signatures[], you can define alias in Field.

class Options(BaseModel):
    signatures: List[Signature] = Field(..., alias="signatures[]")
    header: bool = True
Ph0tonic commented 23 hours ago

Hum, ok thanks, I managed to make it work. My question relied on the use of html forms. And for such, I guess there is no way without using javascript to offer 3 separated inputs for date, name and function. Therefore, in my form I was relying on the traditional way of passing such data with the following form:

<div class="signature">
    <input type="text" name="signatures[][date]">
    <input type="text" name="signatures[][name]">
    <input type="text" name="signatures[][function]">
</div>
<div class="signature">
    <input type="text" name="signatures[][date]">
    <input type="text" name="signatures[][name]">
    <input type="text" name="signatures[][function]">
</div>
<div class="signature">
    <input type="text" name="signatures[][date]">
    <input type="text" name="signatures[][name]">
    <input type="text" name="signatures[][function]">
</div>

And would have expected the following parsing:

signatures:[
   {date:'', function:'', name:''},
   {date:'', function:'', name:''},
   {date:'', function:'', name:''}
]

Do you know any way of structuring a basic form without having to use js ?