Skip to content

Commit

Permalink
Merge pull request #1135 from Zerotask/docs-add-link-for-error-responses
Browse files Browse the repository at this point in the history
docs(response): add link for error responses
  • Loading branch information
vitalik authored Apr 24, 2024
2 parents 4610bea + fe4698a commit 72d9871
Showing 1 changed file with 30 additions and 34 deletions.
64 changes: 30 additions & 34 deletions docs/docs/guides/response/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ def create_user(request, data: UserIn):
user.set_password(data.password)
user.save()
# ... return ?

```

Now let's define the output schema, and pass it as a `response` argument to the `@api.post` decorator:
Expand Down Expand Up @@ -48,20 +47,19 @@ def create_user(request, data: UserIn):

**Django Ninja** will use this `response` schema to:

- convert the output data to declared schema
- validate the data
- add an OpenAPI schema definition
- it will be used by the automatic documentation systems
- and, most importantly, it **will limit the output data** only to the fields only defined in the schema.

- convert the output data to declared schema
- validate the data
- add an OpenAPI schema definition
- it will be used by the automatic documentation systems
- and, most importantly, it **will limit the output data** only to the fields only defined in the schema.

## Nested objects

There is also often a need to return responses with some nested/child objects.

Imagine we have a `Task` Django model with a `User` ForeignKey:

```python hl_lines="6"
```python hl_lines="6"
from django.db import models

class Task(models.Model):
Expand All @@ -72,7 +70,7 @@ class Task(models.Model):

Now let's output all tasks, and for each task, output some fields about the user.

```python hl_lines="13 16"
```python hl_lines="13 16"
from typing import List
from ninja import Schema

Expand All @@ -96,10 +94,10 @@ def tasks(request):

If you execute this operation, you should get a response like this:

```JSON hl_lines="6 7 8 9 16"
```JSON hl_lines="6 7 8 9 16"
[
{
"id": 1,
"id": 1,
"title": "Task 1",
"is_completed": false,
"owner": {
Expand All @@ -109,15 +107,14 @@ If you execute this operation, you should get a response like this:
}
},
{
"id": 2,
"id": 2,
"title": "Task 2",
"is_completed": false,
"owner": null
},
]
```


## Aliases

Instead of a nested response, you may want to just flatten the response output.
Expand Down Expand Up @@ -194,7 +191,6 @@ class Data(Schema):
def resolve_path(obj, context):
request = context["request"]
return request.path

```

if you use this schema for incoming requests - the `request` object will be automatically passed to context.
Expand Down Expand Up @@ -229,7 +225,6 @@ def tasks(request):

See the [async support](../async-support.md#using-orm) guide for more information.


## FileField and ImageField

**Django Ninja** by default converts files and images (declared with `FileField` or `ImageField`) to `string` URL's.
Expand All @@ -243,13 +238,15 @@ class Picture(models.Model):
```

If you need to output to response image field, declare a schema for it as follows:

```python hl_lines="3"
class PictureSchema(Schema):
title: str
image: str
```

Once you output this to a response, the URL will be automatically generated for each object:

```JSON
{
"title": "Zebra",
Expand All @@ -259,26 +256,23 @@ Once you output this to a response, the URL will be automatically generated for

## Multiple Response Schemas


Sometimes you need to define more than response schemas.
In case of authentication, for example, you can return:

- **200** successful -> token
- **401** -> Unauthorized
- **402** -> Payment required
- etc..
- **200** successful -> token
- **401** -> Unauthorized
- **402** -> Payment required
- etc..

In fact, the [OpenAPI specification](https://swagger.io/docs/specification/describing-responses/) allows you to pass multiple response schemas.


You can pass to a `response` argument a dictionary where:

- key is a response code
- value is a schema for that code
- key is a response code
- value is a schema for that code

Also, when you return the result - you have to also pass a status code to tell **Django Ninja** which schema should be used for validation and serialization.


An example:

```python hl_lines="9 12 14 16"
Expand Down Expand Up @@ -337,31 +331,35 @@ You can also create your own range using a `frozenset`:

```python
my_codes = frozenset({416, 418, 425, 429, 451})
...

@api.post('/login', response={200: Token, my_codes: Message})
...
def login(request, payload: Auth):
...
```


## Empty responses

Some responses, such as `204 No Content`, have no body. To indicate the response body is empty mark `response` argument with `None` instead of Schema:
Some responses, such as [204 No Content](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204), have no body.
To indicate the response body is empty mark `response` argument with `None` instead of Schema:

```python hl_lines="1 3"
@api.post("/no_content", response={204: None})
def no_content(request):
return 204, None
```

## Error responses

Check [Handling errors](../errors.md) for more information.

## Self-referencing schemes

Sometimes you need to create a schema that has reference to itself, or tree-structure objects.

To do that you need:

- set a type of your schema in quotes
- use `update_forward_refs` method to apply self referencing types
- set a type of your schema in quotes
- use `update_forward_refs` method to apply self referencing types

```python hl_lines="3 6"
class Organization(Schema):
Expand All @@ -380,13 +378,13 @@ def list_organizations(request):
## Self-referencing schemes from `create_schema()`

To be able to use the method `update_forward_refs()` from a schema generated via `create_schema()`,
the "name" of the class needs to be in our namespace. In this case it is very important to pass
the "name" of the class needs to be in our namespace. In this case it is very important to pass
the `name` parameter to `create_schema()`

```python hl_lines="3"
UserSchema = create_schema(
User,
name='UserSchema', # !!! this is important for update_forward_refs()
name='UserSchema', # !!! this is important for update_forward_refs()
fields=['id', 'username']
custom_fields=[
('manager', 'UserSchema', None),
Expand Down Expand Up @@ -455,6 +453,4 @@ def result_django(request):
@api.get("/something")
def some_redirect(request):
return redirect("/some-path") # !!!!


```

0 comments on commit 72d9871

Please sign in to comment.