Home > OS >  Square bracket along query params in fastapi/flask/nodejs
Square bracket along query params in fastapi/flask/nodejs

Time:12-07

I am so sorry if this is a duplicate question but I barely see it anywhere except this one website. This website originally helps people to make queries in Google Sheet through REST API. Their links go like this example:

spreadsheetID/sheetName?filter[ColumnName]=aiman

I just wonder how to do it in FastAPI especially for params filter[columnName]. The columnName is also a variable which according name of column. I've already read this but cannot figure out it well. Any language also I appreciate.

CodePudding user response:

There is nothing built into the FastAPI to achieve that, but we can write it! We need function that parse parameter:

import re

def parse_param(param, value):
    regex = r"(?P<op>.*)\[(?P<col>.*)\]"
    if m := re.search(r, param):
        return {"op": m.group("op"), "col": m.group("col"), "val": value}
    return {param: value}

Now it's time to use it, the simplest way would be use underlying Starlete request and parse url

from fastapi import Request

@app.get("/sheetName")
def endpoint(r: Request):
    k, v = next(iter(r.query_params.items())) # Assuming there is only one parameter
    print(parse_param(k, v))

If you would like to some FastAPI magic, you have another two options

  1. The middleware
@app.middleware("http")
async def preprocess(request: Request, call_next):
    k, v = next(iter(request.query_params.items()))
    request._query_params = QueryParams(parse_param(k, v))
    request.scope["query_string"] = str(request._query_params).encode("ascii")
    response = await call_next(request)
    return response
  1. Custom request
from fastapi.routing import APIRoute
from starlette.datastructures import QueryParams

class BracketRequest(Request):
    @property
    def query_params(self):
        k, v = next(iter(super().query_params.items()))
        return QueryParams(parse_param(k, v))


class BracketRoute(APIRoute):
    def get_route_handler(self):
        original_route_handler = super().get_route_handler()

        async def custom_route_handler(request: Request):
            request = BracketRequest(request.scope, request.receive)
            return await original_route_handler(request)

        return custom_route_handler

app.router.route_class = BracketRoute

Second solution allows you to assign such logic only for specific routers. In both cases you can use your endpoint with help of FastAPI validation now:

@app.get("/sheetName")
def endpoint(op: str, col: str, val: Any):
    print(op, col, val)

This approach has limitations (like what if there can be more parameters? Or more parameters with brackets?) and exact solutions depends on specific needs, but they should give you enough insight how to solve them.

  • Related