-
-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix OpenAPI for query parameters (#371)
* Clean unused query_param_names * Fix regression for query params * Add extra test for dependencies * Add extra openapi test + is_union definition * Add missing query param docs * Add Path Parameters doc and extra tests * Release notes for version 3.3.4
- Loading branch information
Showing
28 changed files
with
1,005 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
# Extras | ||
# Advanced & Useful | ||
|
||
Here you will find some more details about how to use some specials from Esmerald within your handlers. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# Path Parameters | ||
|
||
Path parameters are those, as the name suggests, parameters that are part of a URL (path) definition. | ||
|
||
You can declare the path parameters (you can think of them as variables) using the same python syntax for strings. | ||
|
||
```python | ||
{!> ../../../docs_src/extras/path/example.py !} | ||
``` | ||
|
||
As you can see, the `user_id` declared in the path was also passed and provided in the function `user`. This is how | ||
you must declare path parameters in Esmerald. | ||
|
||
You can now access the URL: | ||
|
||
```shell | ||
http://127.0.0.1/users/1 | ||
``` | ||
|
||
## Declaration of the parameters | ||
|
||
**Esmerald** being developed on top of [Lilya][lilya] also means that it allows **two** different syntaxes for the declaration | ||
of the parameters. | ||
|
||
=== "Default" | ||
|
||
```python | ||
{!> ../../../docs_src/extras/path/example.py !} | ||
``` | ||
|
||
=== "Less than/Greater than" | ||
|
||
```python | ||
{!> ../../../docs_src/extras/path/example_gt.py !} | ||
``` | ||
|
||
Esmerald allows the use of `{}` and `<>` syntaxes. Both work in an `equal` way and the reasoning for that is only to | ||
allow the users to choose their own preference. | ||
|
||
## Default parameters | ||
|
||
When declaring a controller with path parameters, if no type is specified in the `string` declaration, Esmerald will assume | ||
it will be of type `string`. | ||
|
||
```python | ||
{!> ../../../docs_src/extras/path/example.py !} | ||
``` | ||
|
||
If you wish to specifiy exactly the type for the path parameter, you can do it by liteally specifiying the type of the | ||
parameter. | ||
|
||
```python | ||
{!> ../../../docs_src/extras/path/example_type.py !} | ||
``` | ||
|
||
This will make sure it will enforce the type `int` and throws an error if an invalid integer is provided. | ||
|
||
When providing the path parameters with a proper typing, this will also make sure the [OpenAPI](../openapi.md) documentation | ||
will have the right type for you to test. | ||
|
||
## Custom typing and transformers | ||
|
||
What if you need to create a custom typing that is not natively supported by Esmerald? Well, Esmerald has your back with | ||
the [transformers](../routing/routes.md#custom-transformers). | ||
|
||
This will make sure you have your own transformer for your own unique typing and Esmerald can understand it. | ||
|
||
Since Esmerald is built on top of [Lilya][lilya], that means it also supports natively the same types. | ||
|
||
You can [check here for more details](../routing/routes.md#path-parameters). | ||
|
||
## Enums | ||
|
||
Esmerald also supports `Enum` types as typing. Yes, that's right, natively Esmerald handles Enums for you. This will | ||
trigger automatic validations of Esmerald in case a wrong value is provided. | ||
|
||
```python | ||
{!> ../../../docs_src/extras/path/enum.py !} | ||
``` | ||
|
||
You can now call: | ||
|
||
```shell | ||
http://127.0.0.1/users/admin | ||
``` | ||
|
||
If you, for example, provide something like this: | ||
|
||
```shell | ||
http://127.0.0.1/users/something | ||
``` | ||
|
||
And since `something` is not declared in the Enum type, you will get an error similar to this: | ||
|
||
```json | ||
{ | ||
"detail": "Validation failed for http://127.0.0.1/users/something with method GET.", | ||
"errors": [ | ||
{ | ||
"type": "enum", | ||
"loc": ["item_type"], | ||
"msg": "Input should be 'user' or 'admin'", | ||
"input": "something", | ||
"ctx": {"expected": "'user' or 'admin'"}, | ||
"url": "https://errors.pydantic.dev/2.8/v/enum", | ||
} | ||
], | ||
} | ||
``` | ||
|
||
|
||
[lilya]: https//lilya.dev |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
# Query Parameters | ||
|
||
It is very common to simply want to declare some query parameters in your controllers. Sometimes those are also used | ||
as filters for a given search or simply extra parameters in general. | ||
|
||
## What are query parameters in Esmerald? | ||
|
||
Query parameters are those parameters that are not part of the path parameters and therefore those are automatically | ||
injected as `query` parameters for you. | ||
|
||
```python | ||
{!> ../../../docs_src/extras/query/example1.py !} | ||
``` | ||
|
||
As you can see, the query is a key-pair value that goes after the `?` in the URL and seperated by a `&`. | ||
|
||
Applying the previous example, it would look like this: | ||
|
||
```shell | ||
http://127.0.0.1/users?skip=1&limit=5 | ||
``` | ||
|
||
The previous url will be translated as the following `query_params`: | ||
|
||
- `skip`: with a value of 1. | ||
- `limit`: with a value of 5. | ||
|
||
Since they are an integral part of the URL, it will automatically populate the parameters of the function that corresponds | ||
each value. | ||
|
||
## Declaring defaults | ||
|
||
Query parameters are not by design, part of a fixed URL path and that also means they can assume the following: | ||
|
||
- They can have defaults, like `skip=1` and `limit=5`. | ||
- They can be `optional`. | ||
|
||
In the previous example, the URL had already defaults for `skip` and `limit` and the corresponding typing as per requirement | ||
of Esmerald but what if we want to make them optional? | ||
|
||
There are different ways of achieving that, using the `Optional` or `Union`. | ||
|
||
!!! Tip | ||
from Python 3.10+ the `Union` can be replaced with `|` syntax. | ||
|
||
|
||
=== "Using Optional" | ||
|
||
```python | ||
{!> ../../../docs_src/extras/query/example_optional.py !} | ||
``` | ||
|
||
=== "Using Union" | ||
|
||
```python | ||
{!> ../../../docs_src/extras/query/example_union.py !} | ||
``` | ||
|
||
!!! Check | ||
Esmerald is intelligent enough to understand what is a `query param` and what is a `path param`. | ||
|
||
Now we can call the URL and ignore the `q` or call it when needed, like this: | ||
|
||
**Without query params** | ||
|
||
```shell | ||
http://127.0.0.1/users/1 | ||
``` | ||
|
||
**With query params** | ||
|
||
```shell | ||
http://127.0.0.1/users/1?q=searchValue | ||
``` | ||
|
||
## Query and Path parameters | ||
|
||
Since Esmerald is intelligent enough to distinguish path parameters and query parameters automatically, that also means | ||
you can have multiple of both combined. | ||
|
||
!!! Warning | ||
You can't have a query and path parameters with the same name as in the end, it is still Python parameters being | ||
declared in a function. | ||
|
||
```python | ||
{!> ../../../docs_src/extras/query/example_combined.py !} | ||
``` | ||
|
||
## Required parameters | ||
|
||
When you declare a `query parameter` **without a default** and **without being optional** when you call the URL | ||
it will raise an error of missing value for the corresponding. | ||
|
||
```python | ||
{!> ../../../docs_src/extras/query/example_mandatory.py !} | ||
``` | ||
|
||
If you call the URL like this: | ||
|
||
``` | ||
http://127.0.0.1/users | ||
``` | ||
|
||
It will raise an error of missing value, something like this: | ||
|
||
```json | ||
{ | ||
"detail": "Validation failed for <URL> with method GET.", | ||
"errors": [ | ||
{ | ||
"type": "int_type", | ||
"loc": [ | ||
"limit" | ||
], | ||
"msg": "Input should be a valid integer", | ||
"input": null, | ||
"url": "https://errors.pydantic.dev/2.8/v/int_type" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
Which means, you need to call with the declared parameter, like this, for example: | ||
|
||
```shell | ||
http://127.0.0.1/users?limit=10 | ||
``` | ||
|
||
## Extra with Esmerald params | ||
|
||
Because everything in Esmerald just works you can also add restrictions and limits to your query parameters. For example. | ||
you might want to add a limit into the size of a string `q` when searching not to exceed an X value. | ||
|
||
```python | ||
{!> ../../../docs_src/extras/query/example_query.py !} | ||
``` | ||
|
||
This basically tells that a `q` query parameters must not exceed the length of `10` of an exception will be raised. |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from enum import Enum | ||
|
||
from esmerald import Esmerald, Gateway, JSONResponse, get | ||
|
||
|
||
class UserEnum(Enum): | ||
user = "user" | ||
admin = "admin" | ||
|
||
|
||
@get("/users/{user_type}") | ||
async def read_user(user_type: UserEnum) -> JSONResponse: ... | ||
|
||
|
||
app = Esmerald( | ||
routes=[ | ||
Gateway(read_user), | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from esmerald import Esmerald, Gateway, JSONResponse, get | ||
|
||
|
||
@get("/users/{user_id}") | ||
async def read_user(user_id: str) -> JSONResponse: ... | ||
|
||
|
||
app = Esmerald( | ||
routes=[ | ||
Gateway(read_user), | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from esmerald import Esmerald, Gateway, JSONResponse, get | ||
|
||
|
||
@get("/users/<user_id>") | ||
async def read_user(user_id: str) -> JSONResponse: ... | ||
|
||
|
||
app = Esmerald( | ||
routes=[ | ||
Gateway(read_user), | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from esmerald import Esmerald, Gateway, JSONResponse, get | ||
|
||
|
||
@get("/users/{user_id:int}") | ||
async def read_user(user_id: int) -> JSONResponse: ... | ||
|
||
|
||
app = Esmerald( | ||
routes=[ | ||
Gateway(read_user), | ||
] | ||
) |
Oops, something went wrong.