Question: Is there any way to have custom validation logic in a FastAPI query parameter? example I have a FastAPI app with a bunch of request handlers taking Path components as query parameters. For example: def _raise_if_non_relative_path(path: Path): if path.is_absolute(): raise HTTPException( status_code=409, detail=f"Absolute paths are not allowed, {path} is absolute." ) @app.get("/new",) def new_file(where: Path): _raise_if_non_relative_path(where) # do save a file return Response(status_code=requests.codes.ok) @app.get("/new",) def delete_file(where: Path): _raise_if_non_relative_path(where) # do save a file return Response(status_code=requests.codes.ok)  I was wondering if there is way to ensure that the handler is not even called when the given file path is absolute. Now I have to repeat myself with _raise_if_non_relative_path everywhere. what I tried  fastapi.Query:  This only allows very basic validation (string length and regex). I could define a absolute path regex in this example. But a regex solution is really not generic, I want to validate with a custom function. Subclass pathlib.Path with validation logic in __init__:  This doesn't work, the type given in the type signature is ignored, and the object in my handler is a regular pathlib.PosixPath. Use @app.middleware:  this can work but seems overkill since not all my request handlers deal with Path objects. class RelativePath(pydantic.Basemodel):  I.e. define a class with single path field, which I can validate however I want. Unfortunately, this does not work for query parameters. If I do this, the request handler insists on having a json content body. Or at least that is what the swagger docs say. 

Answer: This is the kind of validation that the Depends dependency management function is well-suited for. It allows you to define dependencies for given view functions, and add logic to validate (and lazily create) those dependencies. This gives a set of composable dependencies that can be re-used in those views where they are required. You can create a relative_where_query dependency, and then depend on that to perform any required validation: from fastapi import Depends, FastAPI, Response, Query from fastapi.exceptions import HTTPException from pathlib import Path import requests app = FastAPI() def relative_where_query(where: Path = Query(...)): if where.is_absolute(): raise HTTPException( status_code=409, detail=f"Absolute paths are not allowed, {where} is absolute." ) return where @app.get("/new") def new_file(where: Path = Depends(relative_where_query)): return Response(status_code=requests.codes.ok)  This gives small, easily readable (and understandable) view functions, while the dependency ("I need a relative path from the where query parameter") has been moved to its own definition. You can then re-use this dependency in every view function that require a relative path from the where query parameter (and you can further decompose and recompose these dependencies further if necessary). Update 2023-05-01: If you want to generalize this handling to decouple the field name from the validation function, you can do that by generating a dynamic dependency. This examples creates a dynamic base model with Pydantic to do it - but there's surely other ways. Since we now raise the error inside a Pydantic validator, we add an exception handler to give a proper error response if the path isn't valid. The magic itself happens inside path_validator - this function takes the name given to it, uses it as a field name in a create_model call - which dynamically creates a Pydantic model from its parameters. This model is then used as a dependency in the controller. The name given as an argument to the function will be the actual parameter name - both when being called (i.e. in the URL in this case) and when the documentation is displayed. The path name in the controller function itself is only relevant inside the function, and isn't used in the documentation or as the query parameter (the field name in the model is used for that). from fastapi import Depends, FastAPI, Response, Query, Request from fastapi.exceptions import HTTPException from fastapi.responses import JSONResponse from pathlib import Path from pydantic import create_model, validator import requests app = FastAPI() class PathNotAbsoluteError(Exception): pass @app.exception_handler(PathNotAbsoluteError) async def value_error_exception_handler(request: Request, exc: PathNotAbsoluteError): return JSONResponse( status_code=400, content={"message": str(exc)}, ) def path_is_absolute(cls, value): if not value.is_absolute(): raise PathNotAbsoluteError("Given path is not absolute") return value def path_validator(param_name): validators = { 'pathname_validator': validator(param_name)(path_is_absolute) } return create_model( "AbsolutePathQuery", **{param_name: (Path, Query(...))}, __validators__=validators, ) @app.get("/path") def new_file(path: Path = Depends(path_validator("where"))): return Response(status_code=requests.codes.ok)  You can now reuse this in any location you want by adding a dependency on a given parameter name: def new_file(path: Path = Depends(path_validator("my_path"))): ... def old_file(path: Path = Depends(path_validator("where"))): ...