Skip to content

Commit 4716902

Browse files
committed
Added a quick start guide
1 parent 8661e8f commit 4716902

File tree

3 files changed

+233
-0
lines changed

3 files changed

+233
-0
lines changed

docs/img/car_api.png

53.4 KB
Loading

docs/img/ellar_framework.png

68.3 KB
Loading

docs/quick-start.md

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
## Requirements
2+
Python >= 3.6
3+
Starlette >= 0.21.0
4+
pydantic >= 1.6
5+
Injector >= 0.16.1
6+
typer >= 0.6.1
7+
tomlkit >=0.11.1
8+
9+
## Virtual Environment
10+
There are different ways to setting up virtual environment in python. So whichever way its setup, its fine.
11+
It is but a necessity for this quick start. I like to use
12+
```shell
13+
python3.7 -m venv venv
14+
```
15+
16+
## Installation
17+
### Poetry Installation
18+
For [Poetry](https://python-poetry.org/) usages
19+
```shell
20+
poetry add ellar
21+
```
22+
23+
### Pip Installation
24+
For normal pip installation
25+
```shell
26+
pip install ellar
27+
```
28+
29+
## Create a project
30+
To create an ellar project, you need to have a `pyproject.toml` available on your root directory.
31+
This is necessary for ellar to store some `metadata` about your project.
32+
### Step 1
33+
For Pip Users, you need to create `pyproject.toml` file
34+
```shell
35+
touch pyproject.toml
36+
```
37+
If you are using `Poetry`, you are ready to go
38+
### Step 2
39+
Run the ellar create project cli command,
40+
```shell
41+
ellar create-project carsite
42+
```
43+
44+
## Run your project
45+
Ellar runs [UVICORN - ASGI Server](https://www.uvicorn.org/) under the hood.
46+
```shell
47+
ellar runserver --reload
48+
```
49+
`--reload` is to watch for file changes
50+
51+
Now go to [http://127.0.0.1:8000](http://127.0.0.1:8000)
52+
![Swagger UI](img/ellar_framework.png)
53+
54+
## Create a project module
55+
A project module is a project app defining a group of controllers or services including templates and static files.
56+
So, now we have a project created, lets add an app to the project.
57+
```shell
58+
ellar create-module car
59+
```
60+
61+
## Add Schema
62+
In `car.schema.py`, lets add some serializer for car input and output data
63+
```python
64+
from ellar.serializer import Serializer
65+
66+
class CarSerializer(Serializer):
67+
name: str
68+
model: str
69+
brand: str
70+
71+
72+
class RetrieveCarSerializer(CarSerializer):
73+
pk: str
74+
```
75+
76+
## Add Services
77+
In `car.services.py`, lets create a dummy repository `CarDummyDB` to manage our car data.
78+
```python
79+
import typing as t
80+
import uuid
81+
from ellar.di import injectable, singleton_scope
82+
83+
84+
@injectable(scope=singleton_scope)
85+
class CarDummyDB:
86+
class CarDummyDBItem:
87+
pk: str
88+
89+
def __init__(self, **data: t.Dict) -> None:
90+
self.__dict__ = data
91+
92+
def __eq__(self, other):
93+
if isinstance(other, CarDummyDB.CarDummyDBItem):
94+
return self.pk == other.pk
95+
return self.pk == str(other)
96+
97+
def __init__(self) -> None:
98+
self._data: t.List[CarDummyDB.CarDummyDBItem] = []
99+
100+
def add_car(self, data: t.Dict) -> str:
101+
pk = uuid.uuid4()
102+
_data = dict(data)
103+
_data.update(pk=str(pk))
104+
item = self.CarDummyDBItem(**_data)
105+
self._data.append(item)
106+
return item.pk
107+
108+
def list(self) -> t.List["CarDummyDB.CarDummyDBItem"]:
109+
return self._data
110+
111+
def update(self, car_id: str, data: t.Dict) -> t.Optional["CarDummyDB.CarDummyDBItem"]:
112+
idx = self._data.index(car_id)
113+
if idx >= 0:
114+
_data = dict(data)
115+
_data.update(pk=str(car_id))
116+
self._data[idx] = self.CarDummyDBItem(**_data)
117+
return self._data[idx]
118+
119+
def get(self, car_id: str) -> t.Optional["CarDummyDB.CarDummyDBItem"]:
120+
idx = self._data.index(car_id)
121+
if idx >= 0:
122+
return self._data[idx]
123+
124+
def remove(self, car_id: str) -> t.Optional["CarDummyDB.CarDummyDBItem"]:
125+
idx = self._data.index(car_id)
126+
if idx >= 0:
127+
return self._data.pop(idx)
128+
```
129+
## Add Controller
130+
In `car.controllers.py`, lets create `CarController`
131+
132+
```python
133+
import typing as t
134+
from ellar.common import Controller, delete, get, put, post
135+
from ellar.core import ControllerBase
136+
from ellar.exceptions import NotFound
137+
from .schemas import CarSerializer, RetrieveCarSerializer
138+
from .services import CarDummyDB
139+
140+
141+
@Controller
142+
class CarController(ControllerBase):
143+
def __init__(self, db: CarDummyDB) -> None:
144+
self.car_db = db
145+
146+
@post("/create", response={200: str})
147+
async def create_cat(self, payload: CarSerializer):
148+
pk = self.car_db.add_car(payload.dict())
149+
return pk
150+
151+
@put("/{car_id:str}", response={200: RetrieveCarSerializer})
152+
async def update_cat(self, car_id: str, payload: CarSerializer):
153+
car = self.car_db.update(car_id, payload.dict())
154+
if not car:
155+
raise NotFound("Item not found")
156+
return car
157+
158+
@get("/{car_id:str}", response={200: RetrieveCarSerializer})
159+
async def get_car_by_id(self, car_id: str):
160+
car = self.car_db.get(car_id)
161+
if not car:
162+
raise NotFound('Item not found.')
163+
return car
164+
165+
@delete("/{car_id:str}", response={204: dict})
166+
async def deleted_cat(self, car_id: str):
167+
car = self.car_db.remove(car_id)
168+
if not car:
169+
raise NotFound('Item not found.')
170+
return 204, {}
171+
172+
@get("/", response={200: t.List[RetrieveCarSerializer]})
173+
async def list(self):
174+
return self.car_db.list()
175+
176+
```
177+
## Register Service and Controller
178+
In `car.module.py`, lets register `CarController` and `CarDummyDB`
179+
180+
```python
181+
from ellar.common import Module
182+
from ellar.core import ModuleBase
183+
from ellar.di import Container
184+
185+
from .controllers import CarController
186+
from .services import CarDummyDB
187+
188+
189+
@Module(
190+
controllers=[CarController],
191+
providers=[CarDummyDB],
192+
routers=[],
193+
)
194+
class CarModule(ModuleBase):
195+
def register_providers(self, container: Container) -> None:
196+
# for more complicated provider registrations
197+
# container.register_instance(...)
198+
pass
199+
```
200+
201+
202+
## Enabling OpenAPI
203+
To start up openapi, we need to go back to project folder in the `carsite.server.py`
204+
then add the following below.
205+
```python
206+
import os
207+
208+
from ellar.constants import ELLAR_CONFIG_MODULE
209+
from ellar.core.factory import AppFactory
210+
from ellar.openapi import OpenAPIDocumentModule, OpenAPIDocumentBuilder
211+
from .root_module import ApplicationModule
212+
213+
application = AppFactory.create_from_app_module(
214+
ApplicationModule,
215+
config_module=os.environ.get(
216+
ELLAR_CONFIG_MODULE, "carsite.config:DevelopmentConfig"
217+
),
218+
)
219+
220+
document_builder = OpenAPIDocumentBuilder()
221+
document_builder.set_title('CarSite API') \
222+
.set_version('1.0.0') \
223+
.set_contact(name='Eadwin', url='https://www.yahoo.com', email='eadwin@gmail.com') \
224+
.set_license('MIT Licence', url='https://www.google.com')
225+
226+
document = document_builder.build_document(application)
227+
module = application.install_module(OpenAPIDocumentModule, document=document)
228+
module.setup_swagger_doc()
229+
```
230+
231+
Now we can test our API at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs#/)
232+
Please ensure your server is running
233+
![Swagger UI](img/car_api.png)

0 commit comments

Comments
 (0)