Maillol / aiohttp-pydantic

Aiohttp View that validates request body and query sting regarding the annotations declared in the View method

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Uncaptured query params

almaslov opened this issue · comments

Hello!
I have got an API with multiple models. I'd like to to implement filters in my handler which would look like this:
GET /api/pets?name.eq=buddy&age.lt=5. Here I'm trying to get all pets named buddy younger than 5 years. There are two problems: my parameter names are not valid python identifiers(yet it could be solved by using _ delimiter). If first problem is solved, the second is lots of combinations to field_name.filter_type to list and they should be listed for every model I would like to filter.
It would be more convenient for me to get all query parameters not captured by keyword arguments, to handle it by myself later. Like this

class Pet(PydanticView):
    def get(self, **filters: str):
        pets = PetModel.filter(filters)
        ....

But It turns out there's no way to express it in my handler signature right now.

In swagger json it looks like this:

{
  "paths": {
    "/api/pets": {
      "get": {
        "parameters": [
          {
            "in": "query",
            "name": "filter",
            "schema": {
              "$ref": "#/components/schemas/FilterQuery"
            },
            "style": "form",
            "explode": true,
            "description": "Filter fields by eq(==), ne(!=), lt(<), le(<=), gt(>), ge(>=) methods",
            "required": false
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "FilterQuery": {
        "type": "object",
        "properties": {
          "param": {
            "type": "string",
            "default": "value"
          }
        },
        "example": {
          "name": "string",
          "id.ge": 1,
          "id.ne": 2,
          "created_at.gt": "2012-12-12T12:12:12+00:00",
          "updated_at.lt": "2021-12-12T12:12:12+00:00"
        }
      }
    }
  }
}

Hello, did you try to use the Group.

class AgeFilter(Group):
    age_gt: int = 0
    age_lt: int = 99

class Pet(PydanticView):
    def get(self, name: AgeFilter):
        pets = PetModel.filter(**name.to_dict())
        ....

https://github.com/Maillol/aiohttp-pydantic#group-parameters

I like the idea to have parameters with a dot such as client.name.eq, returning nested group. I think I will made a feature to aiohttp-pydantic 2

Yes, groups are great and actually I use them as workaround right now. But this is where problem # 2 strikes. If Pet model has 10 fields and I use 6 filters(eq(==), ne(!=), lt(<), le(<=), gt(>), ge(>=)) than my group contains 60 combinations. So I came to crafting PetFilter from Pet model:

def generate_filters_for_model(model_type):
    # some type creation magic
PetFilter = generate_filters_for_model(Pet)
StoreFilter = generate_filters_for_model(Store)
UserFilter = generate_filters_for_model(User)

Each of these filter instances are used for nothing but compiling them to ORM statements. So they are processed by generic code which could operate with simple dict. I believe that additional classes are redundant in this case. Moreover swagger web page is bloated.

My original thought was that having some way to capture undefined query parameters solves both problems I've mentioned. Also it could be useful in other cases, not only filtering.