Ellar - Python ASGI web framework for building fast, efficient and scalable RESTAPIs and server-side application.
Ellar is a lightweight ASGI framework for building efficient and scalable server-side python applications. It supports both OOP (Object-Oriented Programming) and FP (Functional Programming)
Ellar is based on Starlette (ASGI toolkit), a lightweight ASGI framework/toolkit well-suited for developing asynchronous web services with Python.
- Easy to Use: Ellar has a simple and intuitive API that makes it easy to get started with building a fast and scalable web applications or web APIs in Python.
- Dependency Injection (DI): It comes with DI system makes it easy to manage dependencies and reduce coupling between components.
- Pydantic Integration: It is properly integrated with Pydantic, a popular Python library for data validation, to ensure that input data is valid.
- Templating with Jinja2: Ellar provides built-in support for Jinja2 templates, making it easy to create dynamic web pages.
- OpenAPI Documentation: It comes with built-in support for OpenAPI documentation, making it easy to generate
SwaggerorReDocdocumentation for your API. And more can be added with ease if necessary. - Controller (MVC) Architecture: Ellar's controller architecture follows the Model-View-Controller (MVC) pattern, making it easy to organize your code.
- Guards for Authentication and Authorization: It provides built-in support for guards, allowing you to easily implement authentication and authorization in your application.
- Modularity: Ellar follows a modular architecture inspired by NestJS, making it easy to organize your code into reusable modules.
- Asynchronous programming: It allows you to takes advantage of Python's
async/awaitfeature to write efficient and fast code that can handle large numbers of concurrent requests
- Python >= 3.7
- Starlette
- Injector
- Pydantic
For Poetry usages
poetry add ellar-cliFor normal pip installation
pip install ellar-cliTo create an ellar project, you need to have a pyproject.toml available on your root directory.
This is necessary for ellar to store some metadata about your project.
For Pip Users, you need to create pyproject.toml file
ellar new carsiteIf you are using Poetry, at your project root directory with pyproject.toml,
run the ellar create project cli command,
ellar create-project carsiteEllar runs UVICORN - ASGI Server under the hood.
ellar runserver --reload--reload is to watch for file changes
Now go to http://127.0.0.1:8000

For more info on Ellar CLI, click here
A project module is a project app defining a group of controllers or services including templates and static files. So, now we have a project created, lets add an app to the project.
ellar create-module carIn car/schema.py, lets add some serializer for car input and output data
from ellar.common import Serializer
class CarSerializer(Serializer):
name: str
model: str
brand: str
class RetrieveCarSerializer(CarSerializer):
pk: strIn car/services.py, lets create a dummy repository CarDummyDB to manage our car data.
import typing as t
import uuid
from ellar.di import injectable, singleton_scope
@injectable(scope=singleton_scope)
class CarDummyDB:
class CarDummyDBItem:
pk: str
def __init__(self, **data: t.Dict) -> None:
self.__dict__ = data
def __eq__(self, other):
if isinstance(other, CarDummyDB.CarDummyDBItem):
return self.pk == other.pk
return self.pk == str(other)
def __init__(self) -> None:
self._data: t.List[CarDummyDB.CarDummyDBItem] = []
def add_car(self, data: t.Dict) -> str:
pk = uuid.uuid4()
_data = dict(data)
_data.update(pk=str(pk))
item = self.CarDummyDBItem(**_data)
self._data.append(item)
return item.pk
def list(self) -> t.List["CarDummyDB.CarDummyDBItem"]:
return self._data
def update(self, car_id: str, data: t.Dict) -> t.Optional["CarDummyDB.CarDummyDBItem"]:
idx = self._data.index(car_id)
if idx >= 0:
_data = dict(data)
_data.update(pk=str(car_id))
self._data[idx] = self.CarDummyDBItem(**_data)
return self._data[idx]
def get(self, car_id: str) -> t.Optional["CarDummyDB.CarDummyDBItem"]:
idx = self._data.index(car_id)
if idx >= 0:
return self._data[idx]
def remove(self, car_id: str) -> t.Optional["CarDummyDB.CarDummyDBItem"]:
idx = self._data.index(car_id)
if idx >= 0:
return self._data.pop(idx)In car/controllers.py, lets create CarController
import typing as t
from ellar.common import Controller, delete, get, put, post, ControllerBase
from ellar.common.exceptions import NotFound
from .schemas import CarSerializer, RetrieveCarSerializer
from .services import CarDummyDB
@Controller
class CarController(ControllerBase):
def __init__(self, db: CarDummyDB) -> None:
self.car_db = db
@post("/create", response={200: str})
async def create_cat(self, payload: CarSerializer):
pk = self.car_db.add_car(payload.dict())
return pk
@put("/{car_id:str}", response={200: RetrieveCarSerializer})
async def update_cat(self, car_id: str, payload: CarSerializer):
car = self.car_db.update(car_id, payload.dict())
if not car:
raise NotFound("Item not found")
return car
@get("/{car_id:str}", response={200: RetrieveCarSerializer})
async def get_car_by_id(self, car_id: str):
car = self.car_db.get(car_id)
if not car:
raise NotFound('Item not found.')
return car
@delete("/{car_id:str}", response={204: dict})
async def deleted_cat(self, car_id: str):
car = self.car_db.remove(car_id)
if not car:
raise NotFound('Item not found.')
return 204, {}
@get("/", response={200: t.List[RetrieveCarSerializer]})
async def list(self):
return self.car_db.list()In car/module.py, lets register CarController and CarDummyDB
from ellar.common import Module
from ellar.core import ModuleBase
from ellar.di import Container
from .controllers import CarController
from .services import CarDummyDB
@Module(
controllers=[CarController],
providers=[CarDummyDB],
routers=[],
)
class CarModule(ModuleBase):
def register_providers(self, container: Container) -> None:
# for more complicated provider registrations
# container.register_instance(...)
passEllar is not aware of CarModule yet, so we need to add it to the modules list of ApplicationModule at the carsite/root_module.py.
from ellar.common import Module, exception_handler, JSONResponse, Response, IHostContext
from ellar.core import ModuleBase
from ellar.samples.modules import HomeModule
from .apps.car.module import CarModule
@Module(modules=[HomeModule, CarModule])
class ApplicationModule(ModuleBase):
@exception_handler(404)
def exception_404_handler(cls, context: IHostContext, exc: Exception) -> Response:
return JSONResponse(dict(detail="Resource not found."))To start up openapi, we need to go back to project folder in the server.py
then add the following below.
import os
from ellar.constants import ELLAR_CONFIG_MODULE
from ellar.core import AppFactory
from ellar.openapi import OpenAPIDocumentModule, OpenAPIDocumentBuilder, SwaggerDocumentGenerator
from .root_module import ApplicationModule
application = AppFactory.create_from_app_module(
ApplicationModule,
config_module=os.environ.get(
ELLAR_CONFIG_MODULE, "carsite.config:DevelopmentConfig"
),
)
document_builder = OpenAPIDocumentBuilder()
document_builder.set_title('CarSite API') \
.set_version('1.0.0') \
.set_contact(name='Eadwin', url='https://www.yahoo.com', email='eadwin@gmail.com') \
.set_license('MIT Licence', url='https://www.google.com')
document = document_builder.build_document(application)
module = OpenAPIDocumentModule.setup(
document=document,
document_generator=SwaggerDocumentGenerator(),
guards=[]
)
application.install_module(module)Now we can test our API at http://127.0.0.1:8000/docs
Please ensure your server is running

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.
<html>
<body>
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</body>
</html>See the Doc for more examples.
Project is still in development
- Documentation - (in progress)
- Database Plugin with Encode/ORM
