Litestar: A New Python Web Framework

14 Views
English
#python#framework#litestar#ASGI

API – Litestar

Litestar: Introducing a New Python Framework

There are many Python web frameworks for web development. From Django and Flask to the recently popular FastAPI, there are many options. I've been developing applications in Python for about a year now, using FastAPI for my work.

However, I encountered some inconveniences with FastAPI, so I looked for a new framework and discovered Litestar. I was impressed by its lightweight yet extensible structure, so I decided to share my brief experience using it.

In this article, I'd like to share Litestar's features, simple usage, and the pros and cons I've encountered.

 

Why I was looking for a new framework

I've been developing web applications using Python since the second half of last year. When developing a new project, I was debating which framework to use, and many people around me recommended FastAPI. The application I was developing supports serving AI models, and since most developers in this field use FastAPI, I chose it to follow the industry trend.

However, over time, I began to notice some shortcomings with FastAPI, which can be summarized as follows:

lack of functionality

  • First, I was disappointed by the lack of functionality provided at the FastAPI framework level.
  • For example, I wanted to configure middleware that only worked on specific routes, but FastAPI only used global middleware, making it difficult to apply middleware that only worked on specific paths.
  • The lack of event listener functionality at the framework level meant that separate domain-specific concerns required linking a separate library.
  • Furthermore, the route definition method, which relied on dependencies, made mocking difficult for HTTP testing, making it difficult to write tests.
  • Cache support was lacking.

Difference in direction

  • During development, I realized that FastAPI focuses on creating APIs that are as fast as they can be, and typically, the remaining necessary features are implemented directly or by using other libraries.
  • However, in my case, time was limited, and with only one team member familiar with Python, it was difficult to invest time in researching additional features.
  • While searching revealed numerous FastAPI references, it took considerable time to determine whether this alternative would be a suitable solution for us.

Concerns about one-person development governance

  • Another concern was that FastAPI development was heavily reliant on tiangolo. (When will 1.0 be released?)
  • Of course, given the recent team support and active sponsorship, it's hard to say the framework's development is slow.
  • However, most feature-related PRs appear to be being handled by the creator, tiangolo.
  • While having one person primarily manage the code isn't necessarily a problem, I was concerned to see complaints about PR merges being slowed down or important bug fixes being delayed.

Because of these shortcomings, I looked for other alternatives, and among them, I discovered the Litestar framework.

 

Introducing the Litestar Framework

Litestar supports ASGI well and, similar to FastAPI, actively utilizes type hints. In terms of style, it shares many similarities with FastAPI, making it easy for FastAPI users to adapt. Launched on December 7, 2021, it was released under the name "Starlite" until version 1.0, but was renamed to Litestar after feedback suggesting confusion with Starlette. As of October 2024, the latest version is version 2.12.1.

It is managed by the Litestar Org, with five maintainers.

In terms of its positioning, it seems to fall somewhere between Django and FastAPI. While not pursuing a comprehensive ecosystem like Django, it aims for the simplicity of FastAPI. While using it, I noticed a significant amount of attention paid to making customizing the framework's features easy.

 

Installation and Basic Usage

You can install it as follows:

$ pip install "litestar[standard]"

Let's write a simple web API that prints "Hello world" as follows:

# app.py
from litestar import Litestar, get

@get("/")
async def index() -> str:
    return "Hello, world!"

app = Litestar([index])

 

And if you enter the litestar run command in cli, you can see the following screen.

$ litestar run --reload 
Using Litestar app from app:app
Starting server process ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
┌──────────────────────────────┬──────────────────────┐
│ Litestar version             │ 2.12.1               │
│ Debug mode                   │ Disabled             │
│ Python Debugger on exception │ Disabled             │
│ CORS                         │ Disabled             │
│ CSRF                         │ Disabled             │
│ OpenAPI                      │ Enabled path=/schema │
│ Compression                  │ Disabled             │
└──────────────────────────────┴──────────────────────┘
INFO:     Started server process [9697]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

 

You can register a function when registering a Route, but you can also register it based on the Controller class.

# main.py
from litestar import Litestar, Controller, get
from litestar.exceptions import NotFoundException
from dataclasses import dataclass
from typing import List

# Defines the data structure for a Todo item.
# A dataclass is a simple way to create classes that are primarily used to store data.
@dataclass
class Todo:
    id: int
    title: str
    content: str

# This is the initial list of todo items for the app.
# In a real-world application, this data would be stored in a database.
todos: List[Todo] = [
    Todo(1, "Go grocery shopping", "Buy 2 dozen eggs, 1 gallon of milk, and 1 carrot"),
    Todo(2, "Return library books", "Return 'Demian' by Hermann Hesse and '1984' by George Orwell"),
    Todo(3, "Study coding on the weekend", "Read the official Litestar documentation and create examples"),
]

# This controller handles API requests related to the /todos path.
class TodoController(Controller):
    path = "/todos"

    # GET /todos
    # An API endpoint that returns the entire list of todo items.
    @get()
    async def list_todos(self) -> List[Todo]:
        """
        Gets all Todo items.
        """
        return todos

    # GET /todos/{todo_id}
    # An API endpoint that returns a single todo item with a specific ID.
    # Example: /todos/1 -> returns the Todo item with id 1.
    @get("/{todo_id:int}")
    async def get_todo(self, todo_id: int) -> Todo:
        """
        Gets a Todo item by its ID.
        """
        # Finds the Todo object in the list that matches the todo_id.
        for todo in todos:
            if todo.id == todo_id:
                return todo
        
        # If no matching Todo item is found, it raises a 404 Not Found error.
        raise NotFoundException(f"Todo with id {todo_id} not found.")

# GET /
# Handles requests to the root path of the application.
@get("/")
async def index() -> str:
    """
    The entry point of the application. Returns a simple welcome message.
    """
    return "Hello! Welcome to the Litestar Todo List API."

# Creates the Litestar application.
# It registers the index and TodoController as route handlers.
app = Litestar([index, TodoController])

# How to run the server using uvicorn when executing this file directly:
# In your terminal, enter the command: `uvicorn main:app --reload`

 

Litestar Advantages

ASGI support

One of Litestar's greatest strengths, as befitting a modern (?!) framework, is its robust support for Python ASGI at the framework level. Even if you register a route as async , the framework automatically handles it.

# main.py
from litestar import Litestar, get
from typing import Dict

# Defines a route handler for the root path "/"
@get("/")
def hello_world() -> Dict[str, str]:
    """A route handler can be a regular synchronous function."""
    return {"hello": "world"}

# Creates the Litestar application.
# It registers the hello_world function as a route handler.
app = Litestar(route_handlers=[hello_world])

# How to run the server using uvicorn when executing this file directly:
# In your terminal, enter the command: `uvicorn main:app --reload`

Various functions

FastAPI also provides a variety of features out of the box (basically, without requiring extensive configuration). Some of the most convenient features are listed below.

  • DI
    • You can define dependencies in various ways at the application, router, and controller levels.
    • I think it's advantageous because it supports overriding dependencies according to scope.
    • You can conveniently use required dependencies in controllers by registering them during application bootstrapping.
    • One thing that took a bit of getting used to was that DI works based on parameter names, not TypeHints.
  • Event
    • When writing code in an object-oriented/DDD style, I believe it's crucial to define the direction of dependencies between domain areas.
    • At this point, I feel a means of transmitting events from dependent domain areas is essential. Litestar provides framework-level event functionality, which I found particularly helpful.
    • In particular, defining an event as async ensures that the event originator doesn't have to wait for the event receiving logic to complete.
  • OpenAPI
    • FastAPI supports Swagger as its default API documentation tool, and Litestar also supports it. The default Swagger address is /schema/swagger.
    • In addition, various Redoc, Scalar, and Repidoc tools are supported, allowing for easy customization.

I also found the Cache/Guard/OpenTelemetry support useful.

Linking with useful libraries

  • Litestar supports SQLAlchemy connectivity and offers additional plugin functionality.
  • Like FastAPI, Litestar supports data validation via Pydantic. It also supports MessageSpec.
  • The template engine supports Jinja2, Mako, and Minijinja.

Concept

  • Like FastAPI, Litestar allows for quick startup and simple configuration for building web applications.
  • What sets Litestar apart from frameworks like Flask and FastAPI is that it doesn't aim to be a microframework. It offers a variety of features necessary for web application development and provides an interface for easy customization.
  • However, it doesn't aim to be the "next-generation Django," so it's better to think of it as a framework that integrates various features and connects them where appropriate, rather than creating its own complete ecosystem.
  • So, overall, it falls somewhere between "Django" and "FastAPI."

 

Disadvantage

While it would be nice if Litestar had only advantages, no framework satisfies all requirements. So, I've been using it and considering the shortcomings I've experienced.

Lack of references

Because Litestar still has a small user base compared to other frameworks, it's difficult to find references. Comparing Github stars, Django has 79.6k and FastAPI 76.5k, while Litestar only has 5.4k. Therefore, the primary means of finding references are the Litestar-Fullstack example provided in the official repo or by asking questions directly on the Discord community.

Documentation

I feel like the documentation is still a bit unorganized, and the table of contents could be a bit more organized and grouped. Also, the example code in the documentation is structured in a simple manner, so I feel it would be helpful to include more detailed examples and explanations.

 

Summary and Impressions

  • Litestar is a framework that offers new possibilities for Python web development. Like FastAPI, it supports ASGI well, and its easy-to-use structure allowed me to quickly adapt.
  • I wanted a framework with a richer set of features than FastAPI, but without the hurdles of Django, and this framework felt just right.
  • If I had to describe it, it felt like a middle ground between FastAPI and Django.
    I feel like Litestar can easily address the various shortcomings I experienced with FastAPI, and I plan to expand its use in the future.
  • However, this framework is still in its early stages, so there aren't enough references for large-scale projects. The documentation is also lacking, leaving much room for improvement.
  • Nevertheless, I'm excited to see how Litestar will evolve, and I hope other Korean Python web developers will experience its appeal.

 

Note

 

 

 

 

Related Posts