4

note: This question is different than what is asked here, in that I need it to work with swagger.

Given a FastAPI GET endpoint, I want to allow any arbitrary set of url parameters while maintaining swagger support.

My use case is that I want to support a Json:API like set of query parameters such as /api/books/?include=author&sort=name,zip&sort[author]=-lname&fields=name,phone,street

The use of square brackets prevents me from using traditional classes to model query parameters, so I'm directly using the Request object instead. However, I would like to use swagger to test the endpoint. I can't find a way to provide arbitrary url parameters. I'm happy to type them in as a single string.

One would think something like the following;

def books(**params): 
    ....

That gives a curl statement of;

api/books?params=sort%5Bone%5D%3Dtwo'

what I really want is;

api/books?sort&one%5D%3Dtwo'
SteveJ
  • 2,652
  • 1
  • 24
  • 36

2 Answers2

1

You could use an Optional string parameter (book__params in the case below) to pass the query parameters as a single string through OpenAPI (Swagger UI) e.g., include=author&sort=name,zip&sort[author]=-lname&fields=name,phone,street. You can then parse the query data and get a dictionary (with keys and values) as shown below. You can check whether this optional parameter is empty or not to decide whether to read the query params using book__params (meaning that the request is sent through Swagger) or using the Request directly (meaning that the request is sent by typing the URL in the address bar of the browser e.g., http://127.0.0.1:8000/api/books?include=author&sort=name,zip&sort[author]=-lname&fields=name,phone,street, or using some other client app). Please make sure to name that optional (book__params) parameter something unique that wouldn't also exist in the actual parameters.

from fastapi import FastAPI, Request
from typing import Optional
from urllib.parse import parse_qs

app = FastAPI()

@app.get("/api/books")
def books(request: Request, book__params: Optional[str] = None):
    qs = {}
    if book__params is not None:
        q_params  = parse_qs(book__params)
        qs = dict( (k, v if len(v)>1 else v[0] ) 
                    for k, v in q_params.items() )
    else:   
        qs = dict(request.query_params)

    return qs
Chris
  • 4,940
  • 2
  • 7
  • 28
  • Interesting, Chris --thanks for the input. I'll give this some thought, it isn't an exact match but may be close enough to be usable. – SteveJ Jan 25 '22 at 22:26
-1

You could use Query Params

from fastapi import FastAPI
from fastapi.responses import JSONResponse

app = FastAPI()

@app.get("/api/books")
def read_item(sort: str, one: str):
    print(sort, one)
    return JSONResponse(content={
        "message": "Hello"
    })

URL

http://127.0.0.1:8000/api/books/?sort=text&one=text