Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Esmerald #907

Merged
merged 9 commits into from
Dec 12, 2023
4 changes: 2 additions & 2 deletions docs/src/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ Give me an ASGI web app!

piccolo asgi new

FastAPI, Starlette, BlackSheep, and Litestar are currently supported, with more
coming soon.
FastAPI, Starlette, BlackSheep, Litestar and Esmerald are currently supported,
with more coming soon.

-------------------------------------------------------------------------------

Expand Down
8 changes: 4 additions & 4 deletions docs/src/piccolo/asgi/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ Routing frameworks
******************

Currently, `Starlette <https://www.starlette.io/>`_, `FastAPI <https://fastapi.tiangolo.com/>`_,
`BlackSheep <https://www.neoteroi.dev/blacksheep/>`_, and
`Litestar <https://litestar.dev/>`_ are supported.
`BlackSheep <https://www.neoteroi.dev/blacksheep/>`_,
`Litestar <https://litestar.dev/>`_ and `Esmerald <https://esmerald.dev/>`_ are supported.

Other great ASGI routing frameworks exist, and may be supported in the future
(`Quart <https://pgjones.gitlab.io/quart/>`_ ,
Expand All @@ -32,8 +32,8 @@ Other great ASGI routing frameworks exist, and may be supported in the future
Which to use?
=============

All are great choices. FastAPI is built on top of Starlette, so they're
very similar. FastAPI and BlackSheep are great if you want to document a REST
All are great choices. FastAPI and Esmerald are built on top of Starlette, so they're
very similar. FastAPI, BlackSheep and Esmerald are great if you want to document a REST
API, as they have built-in OpenAPI support.

-------------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion piccolo/apps/asgi/commands/new.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), "templates/app/")
SERVERS = ["uvicorn", "Hypercorn"]
ROUTERS = ["starlette", "fastapi", "blacksheep", "litestar"]
ROUTERS = ["starlette", "fastapi", "blacksheep", "litestar", "esmerald"]
ROUTER_DEPENDENCIES = {
"fastapi": ["fastapi>=0.100.0"],
}
Expand Down
111 changes: 111 additions & 0 deletions piccolo/apps/asgi/commands/templates/app/_esmerald_app.py.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import typing as t

from pathlib import Path

from piccolo_admin.endpoints import create_admin
from piccolo_api.crud.serializers import create_pydantic_model
tarsil marked this conversation as resolved.
Show resolved Hide resolved
from piccolo.engine import engine_finder

from esmerald import (
Esmerald,
Include,
Gateway,
JSONResponse,
APIView,
get,
post,
put,
delete
)
from esmerald.config import StaticFilesConfig

from home.endpoints import home
from home.piccolo_app import APP_CONFIG
from home.tables import Task


async def open_database_connection_pool():
try:
engine = engine_finder()
await engine.start_connection_pool()
except Exception:
print("Unable to connect to the database")


async def close_database_connection_pool():
try:
engine = engine_finder()
await engine.close_connection_pool()
except Exception:
print("Unable to connect to the database")


TaskModelIn: t.Any = create_pydantic_model(
table=Task,
model_name='TaskModelIn'
)
TaskModelOut: t.Any = create_pydantic_model(
table=Task,
include_default_columns=True,
model_name='TaskModelOut'
)


class TaskAPIView(APIView):
path: str = "/"
tags: str = ["Task"]

@get("/")
async def tasks(self) -> t.List[TaskModelOut]:
return await Task.select().order_by(Task.id)


@post('/tasks')
async def create_task(self, payload: TaskModelIn) -> TaskModelOut:
task = Task(**payload.dict())
await task.save()
return task.to_dict()


@put('/tasks/{task_id}')
async def update_task(self, payload: TaskModelIn, task_id: int) -> TaskModelOut:
task = await Task.objects().get(Task.id == task_id)
if not task:
return JSONResponse({}, status_code=404)

for key, value in payload.dict().items():
setattr(task, key, value)

await task.save()

return task.to_dict()


@delete('/tasks/{task_id}')
async def delete_task(self, task_id: int) -> JSONResponse:
task = await Task.objects().get(Task.id == task_id)
if not task:
return JSONResponse({}, status_code=404)

await task.remove()

return JSONResponse({})
tarsil marked this conversation as resolved.
Show resolved Hide resolved


app = Esmerald(
routes=[
Gateway("/", handler=home),
Gateway("/tasks", handler=TaskAPIView),
Include(
"/admin/",
create_admin(
tables=APP_CONFIG.table_classes,
# Required when running under HTTPS:
# allowed_hosts=['my_site.com']
),
),
],
static_files_config=StaticFilesConfig(path="/", directory=Path("static")),
on_startup=[open_database_connection_pool],
on_shutdown=[close_database_connection_pool],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import os

import jinja2
from esmerald import MediaType, Request, Response, get
tarsil marked this conversation as resolved.
Show resolved Hide resolved
from esmerald.responses import HTMLResponse

ENVIRONMENT = jinja2.Environment(
loader=jinja2.FileSystemLoader(
searchpath=os.path.join(os.path.dirname(__file__), "templates")
)
)


@get(path="/", include_in_schema=False)
def home(request: Request) -> HTMLResponse:
template = ENVIRONMENT.get_template("home.html.jinja")

content = template.render(title="Piccolo + ASGI",)

return HTMLResponse(content)

Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
{% include '_blacksheep_endpoints.py.jinja' %}
{% elif router == 'litestar' %}
{% include '_litestar_endpoints.py.jinja' %}
{% elif router == 'esmerald' %}
{% include '_esmerald_endpoints.py.jinja' %}
{% endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@
<li><a href="/admin/">Admin</a></li>
<li><a href="/schema/swagger">Swagger API</a></li>
</ul>
<h3>Esmerald</h3>
<ul>
<li><a href="/admin/">Admin</a></li>
<li><a href="/docs/swagger">Swagger API</a></li>
</ul>
</section>
</div>
{% endblock content %}
Loading