Autogenerate API docs for list query parameters in FastAPI

Viewed 51

FastAPI does not generate docs for queries that have array query parameters. I.e: GET /items?filter[name]=foo&filter[category]=bar&sort=-id,name. According to Openapi 3.0 docs they support a deepObject query parameters (/users?id[role]=admin&id[firstName]=Alex). But how to do this with FastAPI?

Schema:

import re

from typing import Sequence, Generic, TypeVar, Dict, List, Optional, Any
from urllib.parse import unquote

from pydantic import BaseModel
from fastapi import Query, Request

class ListQueryParams(BaseModel):
    query: str = Query(None, description="Search query", example='heart', min_length=1)
    sort: List[str] = Query(None, description="Sorting", example='-id', min_length=2)
    filter: Optional[Dict[str, Any]] = Query(dict(), description="Filters")

    def __init__(self, request: Request, **data: Any):
        super().__init__(**data)
        self._set_filter(request)
        self._set_sort(request)

    def _set_filter(self, request: Request):
        unquoted_params = unquote(str(request.query_params))
        filters = re.findall(r'filter\[([a-z0-9-_]{2,})]', unquoted_params, re.IGNORECASE)

        for key in filters:
            value = request.query_params.get(f'filter[{key}]')
            self.filter[key] = value

    def _set_sort(self, request: Request):
        self.sort = [field.strip() for field in request.query_params.get('sort', '').split(',') if field]

Route:

@router.get('', response_model=Page[ItemOut])
def list_items(params: ListQueryParams = Depends(), db: Session = Depends(get_db)):
    return paginate(ItemsManager(db).get_items_list_query(query=params.query, filter=params.filter, sort=params.sort))

Docs page:

Docs

I would like to see a filter parameter with inputs for filed names between square braces and their values as a result in the docs if it is possible.

UPD:

The only solution I see now is to extend the openapi schema manually:

from fastapi.openapi.utils import get_openapi

openapi_schema = get_openapi(...)
paths = openapi_schema['paths']

for path in paths:
    for method in paths[path]:
        if paths[path][method]['operationId'] == 'list_items_v1_items_get':
            paths[path][method]['parameters'].extend([
                {
                    'in': 'query',
                    'name': 'filter[name]',
                    'required': False
                },
                ...

UPD

Still don't know how to autogenerate, so stopped with this solution:

@router.get('', response_model=Page[ItemOut], openapi_extra={
'parameters': [
    {
        'in': 'query',
        'name': 'filter[name]',
        'required': False,
        'schema': {
            'minLength': 1,
            'type': 'string',
            'example': 'foobar'
        }
    },
    ...
0 Answers
Related