Parámetros de Path y Validaciones Numéricas¶
De la misma manera que puedes declarar más validaciones y metadatos para los parámetros de query con Query
, puedes declarar el mismo tipo de validaciones y metadatos para los parámetros de path con Path
.
Importar Path¶
Primero, importa Path
de fastapi
, e importa Annotated
:
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[str | None, Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
🤓 Other versions and variants
from typing import Annotated, Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from typing import Union
from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Tip
Prefer to use the Annotated
version if possible.
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: str | None = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Tip
Prefer to use the Annotated
version if possible.
from typing import Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: Union[str, None] = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Información
FastAPI agregó soporte para Annotated
(y comenzó a recomendar su uso) en la versión 0.95.0.
Si tienes una versión anterior, obtendrás errores al intentar usar Annotated
.
Asegúrate de Actualizar la versión de FastAPI a al menos la 0.95.1 antes de usar Annotated
.
Declarar metadatos¶
Puedes declarar todos los mismos parámetros que para Query
.
Por ejemplo, para declarar un valor de metadato title
para el parámetro de path item_id
puedes escribir:
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[str | None, Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
🤓 Other versions and variants
from typing import Annotated, Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from typing import Union
from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Tip
Prefer to use the Annotated
version if possible.
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: str | None = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Tip
Prefer to use the Annotated
version if possible.
from typing import Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: Union[str, None] = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Nota
Un parámetro de path siempre es requerido ya que tiene que formar parte del path. Incluso si lo declaras con None
o le asignas un valor por defecto, no afectará en nada, siempre será requerido.
Ordena los parámetros como necesites¶
Consejo
Esto probablemente no es tan importante o necesario si usas Annotated
.
Supongamos que quieres declarar el parámetro de query q
como un str
requerido.
Y no necesitas declarar nada más para ese parámetro, así que realmente no necesitas usar Query
.
Pero aún necesitas usar Path
para el parámetro de path item_id
. Y no quieres usar Annotated
por alguna razón.
Python se quejará si pones un valor con un "default" antes de un valor que no tenga un "default".
Pero puedes reordenarlos y poner el valor sin un default (el parámetro de query q
) primero.
No importa para FastAPI. Detectará los parámetros por sus nombres, tipos y declaraciones por defecto (Query
, Path
, etc.), no le importa el orden.
Así que puedes declarar tu función como:
Consejo
Prefiere usar la versión Annotated
si es posible.
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
🤓 Other versions and variants
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Pero ten en cuenta que si usas Annotated
, no tendrás este problema, no importará ya que no estás usando los valores por defecto de los parámetros de la función para Query()
o Path()
.
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
🤓 Other versions and variants
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Tip
Prefer to use the Annotated
version if possible.
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Ordena los parámetros como necesites, trucos¶
Consejo
Esto probablemente no es tan importante o necesario si usas Annotated
.
Aquí hay un pequeño truco que puede ser útil, pero no lo necesitarás a menudo.
Si quieres:
- declarar el parámetro de query
q
sin unQuery
ni ningún valor por defecto - declarar el parámetro de path
item_id
usandoPath
- tenerlos en un orden diferente
- no usar
Annotated
...Python tiene una sintaxis especial para eso.
Pasa *
, como el primer parámetro de la función.
Python no hará nada con ese *
, pero sabrá que todos los parámetros siguientes deben ser llamados como argumentos de palabras clave (parejas key-value), también conocidos como kwargs
. Incluso si no tienen un valor por defecto.
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
🤓 Other versions and variants
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Mejor con Annotated
¶
Ten en cuenta que si usas Annotated
, como no estás usando valores por defecto de los parámetros de la función, no tendrás este problema y probablemente no necesitarás usar *
.
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
🤓 Other versions and variants
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Tip
Prefer to use the Annotated
version if possible.
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Validaciones numéricas: mayor o igual¶
Con Query
y Path
(y otros que verás más adelante) puedes declarar restricciones numéricas.
Aquí, con ge=1
, item_id
necesitará ser un número entero "g
reater than or e
qual" a 1
.
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
🤓 Other versions and variants
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Tip
Prefer to use the Annotated
version if possible.
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*, item_id: int = Path(title="The ID of the item to get", ge=1), q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Validaciones numéricas: mayor que y menor o igual¶
Lo mismo aplica para:
gt
:g
reatert
hanle
:l
ess than ore
qual
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)],
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
🤓 Other versions and variants
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)],
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Tip
Prefer to use the Annotated
version if possible.
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: int = Path(title="The ID of the item to get", gt=0, le=1000),
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
Validaciones numéricas: flotantes, mayor y menor¶
Las validaciones numéricas también funcionan para valores float
.
Aquí es donde se convierte en importante poder declarar gt
y no solo ge
. Ya que con esto puedes requerir, por ejemplo, que un valor sea mayor que 0
, incluso si es menor que 1
.
Así, 0.5
sería un valor válido. Pero 0.0
o 0
no lo serían.
Y lo mismo para lt
.
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
q: str,
size: Annotated[float, Query(gt=0, lt=10.5)],
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if size:
results.update({"size": size})
return results
🤓 Other versions and variants
from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
q: str,
size: Annotated[float, Query(gt=0, lt=10.5)],
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if size:
results.update({"size": size})
return results
Tip
Prefer to use the Annotated
version if possible.
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: int = Path(title="The ID of the item to get", ge=0, le=1000),
q: str,
size: float = Query(gt=0, lt=10.5),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if size:
results.update({"size": size})
return results
Resumen¶
Con Query
, Path
(y otros que aún no has visto) puedes declarar metadatos y validaciones de string de las mismas maneras que con Parámetros de Query y Validaciones de String.
Y también puedes declarar validaciones numéricas:
gt
:g
reatert
hange
:g
reater than ore
quallt
:l
esst
hanle
:l
ess than ore
qual
Información
Query
, Path
y otras clases que verás más adelante son subclases de una clase común Param
.
Todas ellas comparten los mismos parámetros para validación adicional y metadatos que has visto.
Nota técnica
Cuando importas Query
, Path
y otros de fastapi
, en realidad son funciones.
Que cuando se llaman, retornan instances de clases con el mismo nombre.
Así que importas Query
, que es una función. Y cuando la llamas, retorna una instance de una clase también llamada Query
.
Estas funciones están allí (en lugar de usar simplemente las clases directamente) para que tu editor no marque errores sobre sus tipos.
De esa forma puedes usar tu editor y herramientas de programación normales sin tener que agregar configuraciones personalizadas para omitir esos errores.