Open jceipek opened 2 months ago
I think the intended way to do this is to use param: type = Path(...)
directly in the function signature as shown here.
Hi @jceipek
Basically you need to use Path marker (and PathEx to pass EXtras + P param):
from ninja import NinjaAPI, PathEx, P
api = NinjaAPI()
@api.get("/items/{item_id}")
def read_item(request, item_id: PathEx[str, P(example="an example", title="Some Title", description="A description")]):
return {"item_id": item_id}
Note: swagger supports only 1 example (not multiple examples) for path params
I think the intended way to do this is to use
param: type = Path(...)
directly in the function signature as shown here.
@dmartin That doesn't quite work; Path
from from ninja import Path
expects a generic parameter and mypy
warns that one is missing. It does work with param_functions.Path
from from ninja.params import functions as param_functions
.
Basically you need to use Path marker (and PathEx to pass EXtras + P param):
from ninja import NinjaAPI, PathEx, P api = NinjaAPI() @api.get("/items/{item_id}") def read_item(request, item_id: PathEx[str, P(example="an example", title="Some Title", description="A description")]): return {"item_id": item_id}
@vitalik That works as a workaround; thank you!
Is the problem I reported with using Annotated
expected behavior, then? It's especially confusing when usingAnnotated
indirectly; for example:
ItemType = Annotated[str, Field(examples=["an example"], title="Some Title", description="A description")]
...
@api.get("/items/{item_id}")
def read_item(request, item_id: ItemType):
return {"item_id": item_id}
In that case, it seems odd to need to repeat the information like this:
ItemType = Annotated[str, Field(examples=["an example"], title="Some Title", description="A description")]
...
@api.get("/items/{item_id}")
def read_item(request, item_id: PathEx[ItemType, P(example="an example", title="Some Title", description="A description")]):
return {"item_id": item_id}
Note: swagger supports only 1 example (not multiple examples) for path params
Good to know; thanks!
@dmartin That doesn't quite work;
Path
fromfrom ninja import Path
expects a generic parameter. It does work withparam_functions.Path
fromfrom ninja.params import functions as param_functions
.
Ah, sorry for the misinformation there. I have some functions like
def submissions(
request: Request,
id: int = Path(
...,
description="Must be a member of a classroom in which the user is a leader.",
)
):
which seem to be working (the description appears in the OpenAPI spec), but maybe that is simply coincidental.
Is there any documentation about when and how to use different parameter constructs like:
params: MyParams = Query(...)
vs params: Query[MyParams]
vs QueryEx
?
Is there any documentation about when and how to use different parameter constructs like:
params: MyParams = Query(...)
vsparams: Query[MyParams]
vsQueryEx
?
Query
- QueryEx
- is basically the same thing in runtime
it just because it's a special Annotated
alias - mypy does not like it with parameters
Query[type, P(options..)]
is equal to QueryEx[type, P(options)]
- but mypy will give you linting error saying that that's not allowed - I still did not find any useful solution how to overcome this
Describe the bug Given:
I expect "Some Title" and "A description" show up in the generated OpenAPI docs. However, only "an example" shows up in the generated OpenAPI docs.
Versions (please complete the following information):
Root Cause
ninja
'sclass Param(FieldInfo)
inninja.params.models
calls:This ultimately causes a
Path
instance to be created with these_attributes_set
values:Note that the values of
title
anddescription
areNone
.Direct Cause
When
ninja
constructs anOperation
, it creates aViewSignature
, which calls_create_models
. The end of the_create_models
function callsmodel_cls = type(cls_name, (base_cls,), attrs)
. This causes Pydantic'sModelMetaclass
__new__
method to be called, which results in calls toset_model_fields
,collect_model_fields
, andfrom_annotated_attribute
.from_annotated_attribute
callsmerge_field_infos
on a tuple of three elements (I'm not sure why the first two elements are identical):The
Path
element in the tuple has an_attributes_set
attribute containing this dictionary:Note that
title
anddescription
are set toNone
, somerge_field_infos
overwrites the desireddescription
andtitle
withNone
.Potential Solution
This bug disappears if
FieldInfo.__init__
inclass Param(FieldInfo)
does not receiveNone
values in the default case. For example, adding this to the bottom of__init__
inclass Param(FieldInfo)
addresses the immediate problem:I'd be happy to make a pull request making this change, but first I'd like to know if this is an appropriate solution. Is there an easier way to do this?