@@ -43,244 +43,90 @@ Ellar is based on [Starlette (ASGI toolkit)](https://www.starlette.io/), a light
43
43
- Pydantic
44
44
45
45
## ** Installation**
46
- ### Poetry Installation
47
- For [ Poetry] ( https://python-poetry.org/ ) usages
48
-
49
- ``` shell
50
- poetry add ellar-cli
51
- ```
52
-
53
- ### Pip Installation
54
- For normal pip installation
55
- ``` shell
56
- pip install ellar-cli
57
- ```
58
-
59
- ## ** Creating a project**
60
- To create an ellar project, you need to have a ` pyproject.toml ` available on your root directory.
61
- This is necessary for ellar to store some ` metadata ` about your project.
62
-
63
- For Pip Users, you need to create ` pyproject.toml ` file
64
- ``` shell
65
- ellar new carsite
66
- ```
67
- If you are using ` Poetry ` , at your project root directory with ` pyproject.toml ` ,
68
- run the ellar create project cli command,
69
- ``` shell
70
- ellar create-project carsite
71
- ```
72
-
73
- ## ** Run your project**
74
- Ellar runs [ UVICORN - ASGI Server] ( https://www.uvicorn.org/ ) under the hood.
75
- ``` shell
76
- ellar runserver --reload
77
- ```
78
- ` --reload ` is to watch for file changes
79
-
80
- Now go to [ http://127.0.0.1:8000 ] ( http://127.0.0.1:8000 )
81
- ![ Swagger UI] ( https://python-ellar.github.io/ellar/img/ellar_framework.png )
82
-
83
- For more info on Ellar CLI, click [ here] ( https://github.com/python-ellar/ellar-cli )
84
-
85
- ## ** Adding a project module**
86
- A project module is a project app defining a group of controllers or services including templates and static files.
87
- So, now we have a project created, lets add an app to the project.
88
46
``` shell
89
- ellar create-module car
47
+ $( venv ) pip install ellar
90
48
```
91
49
92
- ## ** Add Schema**
93
- In ` car/schema.py ` , lets add some serializer for car input and output data
50
+ ## ** Try This**
94
51
``` python
95
- from ellar.common import Serializer
52
+ import uvicorn
53
+ from ellar.common import Body, Controller, ControllerBase, delete, get, post, put, Serializer, Provide
54
+ from ellar.core import AppFactory
55
+ from ellar.di import injectable, request_scope
56
+ from ellar.openapi import OpenAPIDocumentModule, OpenAPIDocumentBuilder, SwaggerDocumentGenerator
57
+ from pydantic import Field
58
+ from pathlib import Path
59
+
96
60
97
- class CarSerializer (Serializer ):
61
+ class CreateCarSerializer (Serializer ):
98
62
name: str
63
+ year: int = Field(... , gt = 0 )
99
64
model: str
100
- brand: str
101
-
102
-
103
- class RetrieveCarSerializer (CarSerializer ):
104
- pk: str
105
- ```
106
-
107
- ## ** Add Services**
108
- In ` car/services.py ` , lets create a dummy repository ` CarDummyDB ` to manage our car data.
109
- ``` python
110
- import typing as t
111
- import uuid
112
- from ellar.di import injectable, singleton_scope
113
-
114
65
115
- @injectable (scope = singleton_scope)
116
- class CarDummyDB :
117
- class CarDummyDBItem :
118
- pk: str
119
66
120
- def __init__ (self , ** data : t.Dict) -> None :
121
- self .__dict__ = data
122
-
123
- def __eq__ (self , other ):
124
- if isinstance (other, CarDummyDB.CarDummyDBItem):
125
- return self .pk == other.pk
126
- return self .pk == str (other)
127
-
128
- def __init__ (self ) -> None :
129
- self ._data: t.List[CarDummyDB.CarDummyDBItem] = []
130
-
131
- def add_car (self , data : t.Dict) -> str :
132
- pk = uuid.uuid4()
133
- _data = dict (data)
134
- _data.update(pk = str (pk))
135
- item = self .CarDummyDBItem(** _data)
136
- self ._data.append(item)
137
- return item.pk
138
-
139
- def list (self ) -> t.List[" CarDummyDB.CarDummyDBItem" ]:
140
- return self ._data
141
-
142
- def update (self , car_id : str , data : t.Dict) -> t.Optional[" CarDummyDB.CarDummyDBItem" ]:
143
- idx = self ._data.index(car_id)
144
- if idx >= 0 :
145
- _data = dict (data)
146
- _data.update(pk = str (car_id))
147
- self ._data[idx] = self .CarDummyDBItem(** _data)
148
- return self ._data[idx]
149
-
150
- def get (self , car_id : str ) -> t.Optional[" CarDummyDB.CarDummyDBItem" ]:
151
- idx = self ._data.index(car_id)
152
- if idx >= 0 :
153
- return self ._data[idx]
154
-
155
- def remove (self , car_id : str ) -> t.Optional[" CarDummyDB.CarDummyDBItem" ]:
156
- idx = self ._data.index(car_id)
157
- if idx >= 0 :
158
- return self ._data.pop(idx)
159
- ```
160
- ## ** Add Controller**
161
- In ` car/controllers.py ` , lets create ` CarController `
162
-
163
- ``` python
164
- import typing as t
165
- from ellar.common import Controller, delete, get, put, post, ControllerBase
166
- from ellar.common.exceptions import NotFound
167
- from .schemas import CarSerializer, RetrieveCarSerializer
168
- from .services import CarDummyDB
67
+ @injectable (scope = request_scope)
68
+ class CarService :
69
+ def __init__ (self ):
70
+ self .detail = ' a service'
169
71
170
72
171
73
@Controller
172
- class CarController (ControllerBase ):
173
- def __init__ (self , db : CarDummyDB) -> None :
174
- self .car_db = db
175
-
176
- @post (" /create" , response = {200 : str })
177
- async def create_cat (self , payload : CarSerializer):
178
- pk = self .car_db.add_car(payload.dict())
179
- return pk
180
-
181
- @put (" /{car_id: str} " , response = {200 : RetrieveCarSerializer})
182
- async def update_cat (self , car_id : str , payload : CarSerializer):
183
- car = self .car_db.update(car_id, payload.dict())
184
- if not car:
185
- raise NotFound(" Item not found" )
186
- return car
187
-
188
- @get (" /{car_id: str} " , response = {200 : RetrieveCarSerializer})
189
- async def get_car_by_id (self , car_id : str ):
190
- car = self .car_db.get(car_id)
191
- if not car:
192
- raise NotFound(' Item not found.' )
193
- return car
194
-
195
- @delete (" /{car_id: str} " , response = {204 : dict })
196
- async def deleted_cat (self , car_id : str ):
197
- car = self .car_db.remove(car_id)
198
- if not car:
199
- raise NotFound(' Item not found.' )
200
- return 204 , {}
201
-
202
- @get (" /" , response = {200 : t.List[RetrieveCarSerializer]})
203
- async def list (self ):
204
- return self .car_db.list()
205
-
206
- ```
207
- ## ** Register Service and Controller**
208
- In ` car/module.py ` , lets register ` CarController ` and ` CarDummyDB `
209
-
210
- ``` python
211
- from ellar.common import Module
212
- from ellar.core import ModuleBase
213
- from ellar.di import Container
214
-
215
- from .controllers import CarController
216
- from .services import CarDummyDB
217
-
218
-
219
- @Module (
220
- controllers = [CarController],
221
- providers = [CarDummyDB],
222
- routers = [],
223
- )
224
- class CarModule (ModuleBase ):
225
- def register_providers (self , container : Container) -> None :
226
- # for more complicated provider registrations
227
- # container.register_instance(...)
228
- pass
229
- ```
230
-
231
- ## ** Registering Module**
232
- Ellar is not aware of ` CarModule ` yet, so we need to add it to the ` modules ` list of ` ApplicationModule ` at the ` carsite/root_module.py ` .
233
- ``` python
234
- from ellar.common import Module, exception_handler, JSONResponse, Response, IHostContext
235
- from ellar.core import ModuleBase
236
-
237
- from ellar.samples.modules import HomeModule
238
- from .car.module import CarModule
239
-
240
-
241
- @Module (modules = [HomeModule, CarModule])
242
- class ApplicationModule (ModuleBase ):
243
- @exception_handler (404 )
244
- def exception_404_handler (cls , context : IHostContext, exc : Exception ) -> Response:
245
- return JSONResponse(dict (detail = " Resource not found." ))
246
-
247
- ```
248
- ## ** Enabling OpenAPI Docs**
249
- To start up openapi, we need to go back to project folder in the ` server.py `
250
- then add the following below.
251
- ``` python
252
- import os
253
-
254
- from ellar.constants import ELLAR_CONFIG_MODULE
255
- from ellar.core import AppFactory
256
- from ellar.openapi import OpenAPIDocumentModule, OpenAPIDocumentBuilder, SwaggerDocumentGenerator
257
- from .root_module import ApplicationModule
258
-
259
- application = AppFactory.create_from_app_module(
260
- ApplicationModule,
261
- config_module = os.environ.get(
262
- ELLAR_CONFIG_MODULE , " carsite.config:DevelopmentConfig"
263
- ),
74
+ class MotoController (ControllerBase ):
75
+ def __init__ (self , service : CarService):
76
+ self ._service = service
77
+
78
+ @post ()
79
+ async def create (self , payload : CreateCarSerializer = Body()):
80
+ assert self ._service.detail == ' a service'
81
+ result = payload.dict()
82
+ result.update(message = ' This action adds a new car' )
83
+ return result
84
+
85
+ @put (' /{car_id: str} ' )
86
+ async def update (self , car_id : str , payload : CreateCarSerializer = Body()):
87
+ result = payload.dict()
88
+ result.update(message = f ' This action updated # { car_id} car resource ' )
89
+ return result
90
+
91
+ @get (' /{car_id: str} ' )
92
+ async def get_one (self , car_id : str , service : CarService = Provide()):
93
+ assert self ._service == service
94
+ return f " This action returns a # { car_id} car "
95
+
96
+ @delete (' /{car_id: str} ' )
97
+ async def delete (self , car_id : str ):
98
+ return f " This action removes a # { car_id} car "
99
+
100
+
101
+ app = AppFactory.create_app(
102
+ controllers = [MotoController],
103
+ providers = [CarService],
104
+ base_directory = str (Path(__file__ ).parent),
105
+ config_module = dict (REDIRECT_SLASHES = True ),
106
+ template_folder = ' templates'
264
107
)
265
-
266
108
document_builder = OpenAPIDocumentBuilder()
267
- document_builder.set_title(' CarSite API' ) \
268
- .set_version(' 1.0.0 ' ) \
269
- .set_contact(name = ' Eadwin ' , url = ' https://www.yahoo.com' , email = ' eadwin @gmail.com' ) \
109
+ document_builder.set_title(' Ellar API' ) \
110
+ .set_version(' 1.0.2 ' ) \
111
+ .set_contact(name = ' Author ' , url = ' https://www.yahoo.com' , email = ' author @gmail.com' ) \
270
112
.set_license(' MIT Licence' , url = ' https://www.google.com' )
271
113
272
- document = document_builder.build_document(application )
114
+ document = document_builder.build_document(app )
273
115
module = OpenAPIDocumentModule.setup(
274
- document = document,
275
116
document_generator = SwaggerDocumentGenerator(),
117
+ document = document,
276
118
guards = []
277
119
)
278
- application.install_module(module)
120
+ app.install_module(module)
121
+
122
+
123
+ if __name__ == " __main__" :
124
+ uvicorn.run(" main:app" , port = 5000 , reload = True )
279
125
```
280
126
281
- Now we can test our API at [ http://127.0.0.1:8000 /docs ] ( http://127.0.0.1:8000 /docs#/ )
282
- Please ensure your server is running
283
- ![ Swagger UI ] ( https://python-ellar.github.io/ellar/img/car_api.png )
127
+ Now we can test our API at [ http://127.0.0.1:5000 /docs ] ( http://127.0.0.1:5000 /docs#/ )
128
+
129
+ You can also try the [ quick-project ] ( https://python-ellar.github.io/ellar/quick-project/ ) setup to get a good idea of the library.
284
130
285
131
## ** HTML Templating**
286
132
Ellar has built-in support for Jinja2, which is a popular template engine for HTML. This feature allows for easy and efficient HTML templating similar to that of Flask. Jinja2 can be used to create reusable templates, and to insert dynamic data into HTML pages. It also has support for template inheritance, control structures, and other useful features that can help to simplify and streamline the process of creating HTML templates.
0 commit comments