Skip to content

Commit ee25a66

Browse files
committed
28 dec,2022 project doc update
1 parent 51a1639 commit ee25a66

25 files changed

+1152
-195
lines changed
File renamed without changes.
File renamed without changes.

docs/handling-responses/responses.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Tutorial - Handling Responses
2+
3+
## Define a response Schema
4+
5+
**Django Ninja** allows you to define the schema of your responses both for validation and documentation purposes.
6+
7+
We'll create a third operation that will return information about the current Django user.
8+
9+
```Python
10+
class UserSchema(Schema):
11+
username: str
12+
is_authenticated: bool
13+
# Unauthenticated users don't have the following fields, so provide defaults.
14+
email: str = None
15+
first_name: str = None
16+
last_name: str = None
17+
18+
@api.get("/me", response=UserSchema)
19+
def me(request):
20+
return request.user
21+
```
22+
23+
This will convert the Django `User` object into a dictionary of only the defined fields.
24+
25+
### Multiple response types
26+
27+
Let's return a different response if the current user is not authenticated.
28+
29+
```Python hl_lines="2-5 7-8 10 12-13"
30+
class UserSchema(Schema):
31+
username: str
32+
email: str
33+
first_name: str
34+
last_name: str
35+
36+
class Error(Schema):
37+
message: str
38+
39+
@api.get("/me", response={200: UserSchema, 403: Error})
40+
def me(request):
41+
if not request.user.is_authenticated:
42+
return 403, {"message": "Please sign in first"}
43+
return request.user
44+
```
45+
46+
As you see, you can return a 2-part tuple which will be interpreted as the HTTP response code and the data.
47+
48+
!!! success
49+
50+
That concludes the tutorial! Check out the **Other Tutorials** or the **How-to Guides** for more information.
51+
52+
# introduction
53+
# Response Models
54+
# Response Schema

docs/index.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,20 @@
1212

1313
---
1414
## Introduction
15-
Ellar is a lightweight ASGI framework for building efficient and scalable server-side python application.
15+
Ellar is a lightweight ASGI framework for building efficient and scalable server-side python applications.
1616
It supports both OOP (Object-Oriented Programming) and FP (Functional Programming)
1717

18-
Ellar is built around [Starlette](https://www.starlette.io/)(ASGI toolkit) which processes all the HTTP request and background tasks. Although, there is a high level
18+
19+
Ellar is built around [Starlette (ASGI toolkit)](https://www.starlette.io/) which processes all the HTTP requests and background tasks. Although, there is a high level
1920
of abstraction, some concepts of Starlette are still supported.
2021

2122
## Inspiration
22-
Ellar was heavily inspired by [NestJS](https://docs.nestjs.com/) in its simplicity in usage while managing complex project structures and application.
23+
Ellar was heavily inspired by [NestJS](https://docs.nestjs.com/) in its simplicity in usage while managing complex project structures and applications.
2324
It also adopted some concepts of [FastAPI](https://fastapi.tiangolo.com/) in handling request parameters and data serialization with pydantic.
24-
With that said, the aim of Ellar focuses on high level of abstraction of framework APIs, project structures, architectures and speed of handling requests.
25+
With that said, the aim of Ellar focuses on a high level of abstraction of framework APIs, project structures, architectures, and speed of handling requests.
2526

2627
## Installation
27-
To get started, you need to scaffold a project using [Ellar-CLI](https://eadwincode.github.io/ellar-cli/) toolkit. This is recommended for first-time user.
28+
To get started, you need to scaffold a project using [Ellar-CLI](https://eadwincode.github.io/ellar-cli/) toolkit. This is recommended for a first-time user.
2829
The scaffolded project is more like a guide to project setup.
2930

3031
```shell

docs/overview/controllers.md

Lines changed: 49 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11

2-
The Controller is responsible for handling incoming requests and returning responses to client.
3-
The purpose of a controller is to receive specific requests for an application and `ApplicationRouter` decides which controller should handle an incoming request.
2+
The Controller is responsible for handling incoming requests and returning responses to the client.
3+
The purpose of a controller is to receive specific requests for an application `ApplicationRouter`. `ApplicationRouter` on the other hand, decides which `controller` should handle an incoming request.
44

55
![controller description image](../img/controller_description.png)
66

7-
Controllers can also be seen as a router which has many routes registered in it.
7+
Controllers can be said to be a router with many routes registered in them.
88

9-
### Creating a Controller
9+
### **Creating a Controller**
1010
To create a controller, we use classes and decorators. The `Controller` decorator associates classes with a required
1111
`metadata` needed for Ellar to create a routing table
1212

@@ -19,14 +19,11 @@ class UsersController(ControllerBase):
1919
"""We have created a controller for Users"""
2020
```
2121

22-
## Routing
23-
In this section, we are going to highlight the important features of the `@Controller()`, a `class decorator`
24-
for defining a controller. By default, `@Controller()` will create a path prefix `/dogs` gotten from class name in `Dogs`Controller
25-
that will be used to group related routes and minimize duplicate route definition and code repetition.
26-
27-
For example, we may choose to group a set of routes that manage interactions with a customer entity under the route `/users`.
28-
In that case, we could specify the path prefix `/users` in the `@Controller()` decorator so that we don't have to repeat that portion of the path for each route in the file.
22+
## **Routing**
23+
In this section, we are going to highlight key features of the `@Controller()`, a `class decorator`
24+
for defining a controller. By default, `@Controller()` will create a path prefix `/dogs` gotten from the class name in `Dogs`Controller. This will be used to group related routes and minimize duplicate route definitions.
2925

26+
For example, we may choose to group a set of routes that manage interactions with a customer entity under the route `/users`. In that case, we could specify the path prefix `/users` in the `@Controller()` decorator so we don't have to repeat that portion of the path for each route in the controller.
3027

3128
```python
3229
# project_name/apps/dogs/controllers.py
@@ -48,35 +45,36 @@ class DogsController(ControllerBase):
4845
!!! hint
4946
Class Decorators name are capitalized while function/method decorator name are in lower case
5047

51-
The `@get()` HTTP method decorator before the `get_all(self)` method marks `get_all(self)` as HTTP request handler for
52-
a specific endpoint matching HTTP Request of `GET` and the route path. What is the route path of `get_all(self)`? The route
53-
path is determined by concatenating the controller `path prefix` and path specified in the HTTP method function decorator `@get()`.
54-
Since we've declared a prefix for every route `(dogs)`, and haven't added any path information in the decorator(`default='/'`),
55-
Ellar will map `GET /dogs/` requests to this handler
48+
The `@get()` HTTP method decorator before the `get_all(self)` method marks `get_all(self)` as the HTTP request handler that will handle a specific endpoint matching the route path and HTTP method of `GET`.
49+
50+
But what then is the route path of `get_all(self)`? The route path is determined by concatenating the controller `path prefix` and the path specified in the HTTP method function decorator `@get()`.
51+
52+
For example, we've declared a prefix for every route `(dogs)`, and haven't added any path information in the decorator, which means the path will default to `/`. In that case,
53+
Ellar will map `GET /dogs/` requests to the `get_all(self)` handler.
5654

57-
For example, a path prefix of `/users` combined with the decorator `@get('/profile')` would produce a route mapping for requests like
55+
Another example to help make things clear, a path prefix of `/users` combined with the decorator `@get('/profile')` would produce a route mapping for requests like
5856
`GET /users/profile`.
5957

6058

61-
### Overview of HTTP function decorator parameters:
59+
### **Overview of HTTP function decorator parameters:**
6260

6361
`@get(path: str, name: str, include_in_schema: bool, response: t.Union[t.Dict[int, t.Type], t.List[t.Tuple[int, t.Type]], t.Type])`
6462

65-
- `path`: defines path for route mapping. `default='/'`
63+
- `path`: defines the path for route mapping. `default='/'`
6664
- `name`: defines a `name` that will be used to identify this route during URL reversing. default is function name eg: `get_all`
6765
- `include_in_schema`: indicates if an endpoint should be available in OPENAPI docs
68-
- `response`: defines different response `schema`, `status code` and `Response` type that is available on the endpoint.
66+
- `response`: defines different response `schema`, `status code`, and `Response` type that is available on the endpoint.
6967
This is only necessary for OPENAPI documentation. default: `None`
7068

71-
Ellar will always serialize all HTTP handler functions returned data as `json` unless the data returned is `Response` object.
72-
For the above example, `get_all` returned a string. This will be serialized to json with a `status code` 200.
69+
Ellar serializes all route handler returned data to `JSON` unless the data returned is a `Response` object.
70+
For the above example, `get_all` returned a string. This will be serialized to JSON with a status code 200.
7371

74-
75-
## Request Object
72+
## **Request Object**
7673
There are different ways handlers can access client request details:
7774

78-
- Annotation (`parameter_name:Request`)
79-
Ellar will resolve any parameter annotated as `Request` in request handler signature as `Request` object.
75+
### **Annotation (`parameter_name:Request`)**
76+
77+
Ellar will resolve any parameter annotated as `Request` in the request handler signature as a `Request` object.
8078
```python
8179
# project_name/apps/dogs/controllers.py
8280

@@ -93,7 +91,7 @@ class DogsController(ControllerBase):
9391
...
9492
```
9593

96-
- injection (`parameter_name=Req()`)
94+
### **injection (`parameter_name=Req()`)**
9795

9896
We can also inject request object to any handler by using `@Req` decorator in handler signature.
9997
```python
@@ -113,9 +111,9 @@ class DogsController(ControllerBase):
113111
...
114112
```
115113

116-
- controllers context
114+
### **Controllers Context**
117115

118-
During request handler execution, `Execution Context` is available on the Controller instance and `request` object can be gotten from the context.
116+
During request handler execution, `Execution Context` is available on the Controller instance and the `request` object can be gotten from the context.
119117
```python
120118
# project_name/apps/dogs/controllers.py
121119

@@ -143,13 +141,13 @@ Other request `handler` signature injectors
143141
| `Header()` | pydantic field - resolves required Request `header` parameters |
144142
| `Query()` | pydantic field - resolves required Request `query` parameters |
145143
| `File()` | pydantic field - resolves required Request `body` parameters with content-type=`x-www-form-urlencoded` |
146-
| `Ctx()` | Data-transfer-object or Serializers declarations. |
144+
| `Ctx()` | Injects `ExecutionContext`. |
147145
| `Cookie()` | pydantic field - resolves required Request `cookie` parameters |
148146
| `Session()` | injects Request session data |
149147
| `Host()` | injects Request clients host |
150148
| `Provide()` | injects services |
151149

152-
## Resource
150+
## **Resource**
153151

154152
Let add create endpoint to our `DogsController` resource.
155153
```python
@@ -171,9 +169,10 @@ class DogsController(ControllerBase):
171169
...
172170
```
173171

174-
### HTTP Methods
172+
### **HTTP Methods**
175173

176174
Ellar provides decorators for all the standard HTTP methods:
175+
177176
- `@get` - `GET` HTTP method
178177
- `@post` - `POST` HTTP method
179178
- `@put` - `PUT` HTTP method
@@ -184,10 +183,9 @@ Ellar provides decorators for all the standard HTTP methods:
184183
- `@head` - `HEAD` HTTP method
185184
- `@http_route` - allows one or more HTTP methods combination, eg: `@http_route(methods=['PUT', 'PATCH'])`
186185

186+
## **Asynchronicity**
187187

188-
## Asynchronicity
189-
190-
Ellar support modern asynchronous programming in python using `async` and `await` syntax.
188+
Ellar supports modern asynchronous programming in python using `async` and `await` syntax.
191189

192190
```python
193191
# project_name/apps/dogs/controllers.py
@@ -207,9 +205,10 @@ class DogsController(ControllerBase):
207205
return 'This action returns all dogs'
208206
...
209207
```
210-
## Request Payload
211208

212-
Let's use `@Body()` to defined required data to create a dog in our previous `create`(POST) endpoint.
209+
## **Request Payload**
210+
211+
Let's use `@Body()` to define the required data to create a dog in our previous `create`(POST) endpoint.
213212
Before that, we need to define our data input/output serializers
214213

215214
```python
@@ -249,11 +248,13 @@ async def create(self, payload: CreateDogSerializer = Body()):
249248
return 'This action adds a new dog'
250249
```
251250

252-
`CreateDogSerializer`, a pydantic type, so fields(`name`, `age`, `breed`) validations according to defined types and
253-
specifications is supported out of the box.
251+
`CreateDogSerializer` is a pydantic type. These means `name`, `age` and `breed` fields are type validated out of the box.
252+
253+
It's important to note the way we used `CreateDogSerializer` as a type annotation of the `payload` parameter in the `create` route handler method.
254+
Ellar will compute values for all the route handler parameters and validates them based on the annotated types before executing the handler. 
254255

255-
It's important to note the way we used `CreateDogSerializer` as a type annotation to `payload` parameter in `create` method.
256-
During request Ellar computes the route handler signatures and validates them to the annotated types before executing the handler.
256+
!!! info
257+
if a parameter is not annotated, it will be assumed as a `string` type
257258

258259
![CreateDogSchema](../img/create-dog-schema.png)
259260

@@ -295,12 +296,15 @@ class DogsController(ControllerBase):
295296
return f'This action returns all dogs at limit={query.limit}, offset={query.offset}'
296297

297298
```
298-
## Linking Controller
299+
## **Linking Controller**
300+
301+
In the previous page, we already wired our `dogs` module (`DogsModule`) to `ApplicationModule` in `project_name/root_module` but this time we shall be adding things to the `DogsModule`. To keep things more simple, organized, and modular.
302+
303+
Let's register `DogsController` to `DogsModule`.
304+
`@Module()` takes `controllers` as a parameter which is an array of the `ControllerBase` type.
299305

300-
In the previous page, we already wired our `dogs` module (`DogsModule`) to `ApplicationModule` in `project_name/root_module`
301-
So, lets link `DogsController` to `DogsModule`.
306+
In the `dogs` module,
302307

303-
It is good to note that controllers always belong to a module, which is why we include the `controllers` array within the @Module() decorator.
304308
```python
305309
# project_name/apps/dogs/module.py
306310

0 commit comments

Comments
 (0)