Recap and assembling the final application#

So far we have looked at the different parts of the application in isolation, but now it’s time to put them all together and assemble a complete application.

Final application#

app.py#
 1from dataclasses import dataclass
 2from typing import List, Optional
 3
 4from litestar import Litestar, get, post, put
 5from litestar.exceptions import NotFoundException
 6
 7
 8@dataclass
 9class TodoItem:
10    title: str
11    done: bool
12
13
14TODO_LIST: List[TodoItem] = [
15    TodoItem(title="Start writing TODO list", done=True),
16    TodoItem(title="???", done=False),
17    TodoItem(title="Profit", done=False),
18]
19
20
21def get_todo_by_title(todo_name) -> TodoItem:
22    for item in TODO_LIST:
23        if item.title == todo_name:
24            return item
25    raise NotFoundException(detail=f"TODO {todo_name!r} not found")
26
27
28@get("/")
29async def get_list(done: Optional[bool] = None) -> List[TodoItem]:
30    if done is None:
31        return TODO_LIST
32    return [item for item in TODO_LIST if item.done == done]
33
34
35@post("/")
36async def add_item(data: TodoItem) -> List[TodoItem]:
37    TODO_LIST.append(data)
38    return TODO_LIST
39
40
41@put("/{item_title:str}")
42async def update_item(item_title: str, data: TodoItem) -> List[TodoItem]:
43    todo_item = get_todo_by_title(item_title)
44    todo_item.title = data.title
45    todo_item.done = data.done
46    return TODO_LIST
47
48
49app = Litestar([get_list, add_item, update_item])
app.py#
 1from dataclasses import dataclass
 2
 3from litestar import Litestar, get, post, put
 4from litestar.exceptions import NotFoundException
 5
 6
 7@dataclass
 8class TodoItem:
 9    title: str
10    done: bool
11
12
13TODO_LIST: list[TodoItem] = [
14    TodoItem(title="Start writing TODO list", done=True),
15    TodoItem(title="???", done=False),
16    TodoItem(title="Profit", done=False),
17]
18
19
20def get_todo_by_title(todo_name) -> TodoItem:
21    for item in TODO_LIST:
22        if item.title == todo_name:
23            return item
24    raise NotFoundException(detail=f"TODO {todo_name!r} not found")
25
26
27@get("/")
28async def get_list(done: bool | None = None) -> list[TodoItem]:
29    if done is None:
30        return TODO_LIST
31    return [item for item in TODO_LIST if item.done == done]
32
33
34@post("/")
35async def add_item(data: TodoItem) -> list[TodoItem]:
36    TODO_LIST.append(data)
37    return TODO_LIST
38
39
40@put("/{item_title:str}")
41async def update_item(item_title: str, data: TodoItem) -> list[TodoItem]:
42    todo_item = get_todo_by_title(item_title)
43    todo_item.title = data.title
44    todo_item.done = data.done
45    return TODO_LIST
46
47
48app = Litestar([get_list, add_item, update_item])

Recap#

app.py#
28@get("/")
29async def get_list(done: Optional[bool] = None) -> List[TodoItem]:
30    if done is None:
31        return TODO_LIST
32    return [item for item in TODO_LIST if item.done == done]

A route handler set up with get("/") responds to GET requests and returns a list of all items on our TODO-list. The optional query parameter done allows filtering the items by status. The type annotation of bool converts the query parameter into a bool, and wrapping it in Optional makes it optional.

app.py#
35@post("/")
36async def add_item(data: TodoItem) -> List[TodoItem]:
37    TODO_LIST.append(data)
38    return TODO_LIST

A route handler set up with post("/") responds to POST requests and adds an item to the TODO-list. The data for the new item is received via the request data, which the route handler accesses by specifying the data parameter. The type annotation of TodoItem means the request data will parsed as JSON, which is then used to create an instance of the TodoItem dataclass, which - finally - gets passed into the function.

app.py#
41@put("/{item_title:str}")
42async def update_item(item_title: str, data: TodoItem) -> List[TodoItem]:
43    todo_item = get_todo_by_title(item_title)
44    todo_item.title = data.title
45    todo_item.done = data.done
46    return TODO_LIST

A route handler set up with put("/{item_title:str}"), making use of a path parameter, responds to PUT requests on the path /some todo title, where some todo title is the title of the TodoItem you wish to update. It receives the value of the path parameter via the function parameter of the same name item_title. The :str suffix in the path parameter means it will be treated as a string. Additionally, this route handler receives data of a TodoItem the same way as the POST handler.

app.py#
49app = Litestar([get_list, add_item, update_item])

An instance of Litestar is created, including the previously defined route handlers. This app can now be served using an ASGI server like uvicorn, which can be conveniently done using Litestar’s CLI by executing the litestar run command.

Next steps#

This tutorial covered some of the fundamental concepts of Litestar. For a more in-depth explanation of these topics, refer to the Usage Guide.