[Python]Built Todo App with FastAPI 😃
Tags: python, fastapi, react, chakraui
Published: 2021-12-21 21:49:21

![todo app front view](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hr06mtdpth42lxe4v2rk.png)

As the title says, I tried to create a TODO list with FastAPI.

Originally, I heard that FastAPI's automatic document　generation feature is good, and I was interested in it.

[Backend]
https://github.com/momonoki1990/fastapi-todo-list-api

[Frontend]
https://github.com/momonoki1990/fastapi-todo-list-frontend

I didn't really need it because I just wanted to try out FastAPI, but I made a front-end for it as well.
I think it's more exciting to have a front-end as well.

※(2022/01/06)I added user register and login function to the backend, but the frontend did not follow those new functions, so the frontend barely works now 😢


## Automatic interactive API documentation

If you start the server and go to `/docs`, you can access the API documentation.
You can see a list of request and response formats for each resource, and by clicking the "Try it out" button, you can actually execute the request.

The generation of this document itself is done by simply describing the API routing in a formatted manner.

```python:/src/routers/task.py
@router.get("", response_model=List[task_schema.TaskResponse])
async def list_tasks(db: AsyncSession = Depends(get_db)):
    return await task_crud.get_tasks(db)
```

For example, in the above code, the type of the response body is set by setting `response_model=List[task_schema.TaskResponse]`.

```python:/src/schema/task.py
from pydantic import BaseModel, Field

class TaskResponse(TaskBase):
    id: int = Field(..., gt=0, example=1)
    done: bool = Field(False, description="done task or not")

    class Config:
        orm_mode = True
```

`task_schema.TaskResponse` is a class that inherits from Pydantic's BaseModel and sets python type hints in its member variables.
It also allows you to add validation and parameter descriptions to an instance called Filed, which will be reflected in the documentation.

If you set `orm_mode = True`, the ORM (SQLAlchemy in this case) model object will be converted to Pydantic response object.
If you do not set it, you will get a validation error.


![response](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m50zqkeq12j651urww4i.png)

![schema](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z4e2wvnppe1tl5cy6wqe.png)

It was the first time for me to create an API in Python, but I was pleasantly surprised at how intuitive it was to write, how detailed validation could be set by simply passing values as keyword arguments, and how the documentation was automatically generated.


## SQLAlchemy

I tried to use SQLAlchemy as an ORM this time, but at first I didn't know what to read in the official documentation...

To begin with, are there two types of SQLAlchemy ORM and SQL Alchemy Core, and does the latter write down SQL directly?

In the tutorial, ORM and Core are written mixed together, and at first I didn't know which one was which. Moreover, the way to write queries in ORM seems to have 2.0 style and 1.x style, and I didn't know which one was which.

However, once I realized that there are ORM and Core, 1.4 style and 2.0 style, and that I can write 2.0 style queries by setting `future=True` in 1.4, I knew where to look in the documentation. I also understood that `engine` is a setting passed to the DB, and `session` is a setting that holds the `engine` setting.

About driver for async process, it seems that aiomysql has stopped being updated and asyncmy is recommended.

![Warning on aiomysql](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hwsrc4m2jt6bf2k1e5vj.png)


![asyncmy is recommended](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dbrmsb0vikd81jc6trnl.png)

(At the bottom of the [top page for each version](https://docs.sqlalchemy.org/en/14/), there is Dialect Documentation, which describes the settings and drivers for each DB.)

## Poetry, black, tox, DB container as test environment

I used the package manager Poery and a formatter called black.

Since the default package manager in tox, a test management tool, is the standard python pip, I set the `install_command` to install the dependent libraries for each test environment using poetry, as shown below.

```ini:tox.ini
[tox]
skipsdist = true
envlist = flake8, py310
install_command = poetry install -D {packages}

[testenv]
deps = pytest
allowlist_externals = poetry
commands =
    poetry install
    poetry run pytest tests/

[testenv:flake8]
deps = flake8
commands =
    poetry run flake8 src/
```

I like black because it needs no settings.
(max-line-length: 88 is too short?)

Although it is not related to the Python development tools above, I used a Docker container for the test environment DB.

(It's almost the same as the DB container for development, except that it's not persisted in volume.)

```yml:docker-compose.yml
db-test:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: "todo"
      MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
      TZ: "Asia/Tokyo"
    volumes:
      - ./my.conf:/etc/mysql/conf.d/my.cnf
    ports:
      - 33050:3306
```

## By the way, about frontend(Vite, Chakra UI)

I used a setup tool called [Vite](https://vitejs.dev/) because I heard it was faster and better than create-react-app. I do think it was faster until the template was created.

[Create react app vs Vite](https://dev.to/keefdrive/create-react-app-vs-vite-2amn)

I heard that you can write CSS like Tailwind, and I was curious about it, so I gave it a try.
Like the following `gridGap` and `py`(padding-top,bottom), it seems to be possible to write all CSS as React props, and I personally like it because it seems to be intuitive and I don't have to worry about class names like Tailwind CSS.
I also found `VStack` `HStack` for creating horizontal and vertical flex containers useful.

```tsx:App.tsx
<div className="App">
      <Container>
        <VStack gridGap="8" py="16">
          <Heading as="h1" size="4xl">
            My Todo List
          </Heading>
          <InputForm tasks={tasks} setTasks={setTasks} />
          <List tasks={tasks} setTasks={setTasks} />
        </VStack>
      </Container>
    </div>
```