Heroes tutorial with FastAPI, SqlModel, postgresql 14 and docker-compose
SqlModel 의 Hero 튜토리얼을 FastAPI 프레임워크로 구현한 프로젝트
<그림> FastAPI /docs 화면 |
$ psql -d company_db -U tonyne -h localhost -p 5432 -W
Password:
psql (14.5)
Type "help" for help.
company_db=# select * from hero;
name | secret_name | age | id
------------+------------------+-----+----
Deadpond | Dive Wilson | | 1
Rusty-Man | Tommy Sharp | 48 | 2
Dormammu | Unknown | | 3
Spider-Boy | Pedro Parqueador | 21 | 4
(4 rows)
{: width="580"} |
---|
<그림> Vue /heroes 화면 |
# insert with HeroCreate
$ curl -X POST "http://localhost:58000/heroes/" -H "Content-Type: application/json" -d '''
{"name": "ABC Teacher", "secret_name": "foo bar", "age": 35}
'''
{"name":"ABC Teacher","secret_name":"foo bar","age":35,"id":5}%
# select by ID=5
$ curl -X GET "http://localhost:58000/hero/5"
{"name":"ABC Teacher","secret_name":"foo bar","age":35,"id":5}%
# update whole-data by ID=5
$ curl -X PATCH "http://localhost:58000/heroes/5" -H "Content-Type: application/json" -H 'Accept: application/json' -d '''
{"name": "ABC Teacher (Extra)", "secret_name": "foo bar", "age": 55}
'''
{"name":"ABC Teacher","secret_name":"foo bar","age":35,"id":5}%
# update partial-data by ID=5
$ curl -X PATCH "http://localhost:58000/heroes/5" -H "Content-Type: application/json" -H 'Accept: application/json' -d '''
{"name": "ABC Super Teacher (Extra)"}
'''
{"name":"ABC Super Teacher (Extra)","secret_name":"foo bar","age":55,"id":5}%
# select by ID=5
$ curl -X GET -H 'Accept: application/json' "http://localhost:58000/hero/5"
{"name":"ABC Teacher Teacher (Extra)","secret_name":"foo bar","age":55,"id":5}%
# delete by ID=5
$ curl -X DELETE -H 'Accept: application/json' "http://localhost:58000/heroes/5"
{"ok":true}%
# select by ID=5 => 404 Error
$ curl -X GET -H 'Accept: application/json' "http://localhost:58000/hero/5"
{"detail":"Hero not found"}%
- GET
/heroes/last
- GET
/heroes
- GET
/hero/2
$ curl -X GET "http://localhost:58000/heroes/last"
{"name":"Spider-Boy","secret_name":"Pedro Parqueador","age":21,"team_id":null,"id":4}%
- select with relations : GET
/heroes/1
{
"name": "Deadpond",
"secret_name": "Dive Wilson",
"age": null,
"team_id": 1,
"id": 1,
"team": {
"name": "서울팀",
"headquarters": "종로구",
"id": 1
}
}
$ curl -X POST "http://localhost:8000/teams/" -H "Content-Type: application/json" -d '''
{"name": "뉴욕팀", "headquarters": "뉴욕시청", "heroes": []}
'''
{"name":"뉴욕팀","headquarters":"뉴욕시청","id":6}%
$ curl -X POST "http://localhost:8000/teams/" -H "Content-Type: application/json" -d '''
{"name": "뉴욕팀", "headquarters": "뉴욕시청", "heroes": [
{"name":"Spider-Boy","secret_name":"Pedro Parqueador","age":21,"id":4}
]}
'''
{"name":"뉴욕팀","headquarters":"뉴욕시청","id":7}%
# update partial-data by ID=5
$ curl -X PATCH "http://localhost:8000/teams/6" -H "Content-Type: application/json" -H 'Accept: application/json' -d '''
{"name": "뉴욕팀 Super", "headquarters": "뉴욕시청 공원", "heroes": [
{"name":"Spider-Boy","secret_name":"Pedro Parqueador","age":21,"id":4}
]}
'''
{"name":"뉴욕팀 Super","headquarters":"뉴욕시청 공원","id":6}%
# delete by ID=5
$ curl -X DELETE -H 'Accept: application/json' "http://localhost:58000/teams/5"
{"ok":true}%
# select by ID=5 => 404 Error
$ curl -X GET -H 'Accept: application/json' "http://localhost:58000/teams/5"
{"detail":"Team not found"}%
- GET
/teams/last
- GET
/teams
- GET
/team/2
$ curl -X GET "http://localhost:58000/teams/last"
{"name":"Spider-Boy","secret_name":"Pedro Parqueador","age":21,"team_id":null,"id":4}%
- select with relations : GET
/teams/1
{
"name": "서울팀",
"headquarters": "종로구",
"id": 1,
"heroes": [
{
"name": "Deadpond",
"secret_name": "Dive Wilson",
"age": null,
"team_id": 1,
"id": 1
},
{
"name": "Rusty-Man",
"secret_name": "Tommy Sharp",
"age": 48,
"team_id": 1,
"id": 2
}
]
}
- delete
select(Hero).where(Hero.name.match("%Tutorial%"))
- delete
select(Team).where(Team.name.match("%Tutorial%"))
- create teams: ['Tutorial Preventers', 'Tutorial Z-Force']
- create heroes: ['Tutorial Deadpond', 'Tutorial Rusty-Man', 'Tutorial Spider-Boy']
- 'Tutorial Deadpond'.team = 'Tutorial Z-Force'
- 'Tutorial Rusty-Man'.team = 'Tutorial Preventers'
- select hero
select(Hero).where(Hero.name == "Tutorial Spider-Boy")
- select team
select(Team).where(Team.id == hero_spider_boy.team_id)
- update hero "Tutorial Spider-Boy"
- hero_spider_boy.team = team_preventers (팀 배정)
- delete team "Tutorial Preventers"
- updated hero with none team
- test_hello : fastapi 작동 여부
- test_hero : GET
/heroes/last
작동 여부와 HeroRead 변환 - test_aiohttp_with_every_client : 1000 번 GET
/heroes/
호출- resp.status == 200 검사
$ poetry run pytest tests --log-cli-level=DEBUG
============================== test session starts ===============================
platform darwin -- Python 3.9.13, pytest-7.1.3, pluggy-1.0.0
rootdir: /Users/bgmin/Workspaces/python/sqlmodel/sqlmodel-pg-api/smp-api
plugins: anyio-3.6.1
collected 6 items
tests/main_test.py::test_hello
tests/main_test.py::test_read_items
tests/main_test.py::test_read_item
tests/main_test.py::test_create_item
tests/main_test.py::test_update_item
tests/main_test.py::test_delete_item
tests/main_test.py ...... [100%]
=============================== 6 passed in 0.64s ================================
- test_read_items, test_read_item : select 테스트
- test_create_item : create 테스트
- test_update_item : update 테스트
- test_delete_item : delete 테스트
- test_read_groups, test_read_group : select 테스트
- test_create_group : create 테스트
- test_update_group : update 테스트
- test_delete_group: delete 테스트
$ curl -F 'file=@../assets/data/test.csv' -X POST "http://localhost:58000/files/upload"
[{"name":"Alice","age":"20","height":"62","weight":"120.6","_id":"1"},{"name":"Freddie","age":"21","height":"74","weight":"190.6","_id":"2"},{"name":"Bob","age":"17","height":"68","weight":"120.0","_id":"3"}]%
$ curl -X GET "http://localhost:8000/files/test"
[{"_id":"1","name":"Alice","age":20,"height":62,"weight":120.6},{"_id":"2","name":"Freddie","age":21,"height":74,"weight":190.6},{"_id":"3","name":"Bob","age":17,"height":68,"weight":120.0}]%
$ curl -X POST "http://localhost:8000/books/" -H "Content-Type: application/json" -d '''{ "_id": "066de609-b04a-4b30-b46c-32537c7f1f6e",
"title": "Don Quixote",
"author": "Miguel de Cervantes",
"synopsis": "..."
}
'''
{"_id":"066de609-b04a-4b30-b46c-32537c7f1f6e","title":"Don Quixote","author":"Miguel de Cervantes","synopsis":"..."}%
$ curl -X PUT "http://localhost:8000/books/066de609-b04a-4b30-b46c-32537c7f1f6e" -H "Content-Type: application/json" -d '''{
"title": "Don Quixote",
"author": "Miguel de Cervantes",
"synopsis": "Don Quixote is a Spanish novel by Miguel de Cervantes..."
}
'''
{"_id":"066de609-b04a-4b30-b46c-32537c7f1f6e","title":"Don Quixote","author":"Miguel de Cervantes","synopsis":"Don Quixote is a Spanish novel by Miguel de Cervantes..."}%
$ curl -X GET "http://localhost:8000/books/"
[{"_id":"066de609-b04a-4b30-b46c-32537c7f1f6e","title":"Don Quixote","author":"Miguel de Cervantes","synopsis":"Don Quixote is a Spanish novel by Miguel de Cervantes..."}]%
# 도커 컴포즈에서 linux/amd64 이미지 생성 (Mac M1)
$ env DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose build
[+] Building 650.5s (20/21)
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 32B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 34B 0.0s
=> [internal] load metadata for docker.io/library/python:3.9-slim 3.1s
...
$ docker compose up -d
[+] Running 2/2
⠿ Container smp-db Created 0.0s
⠿ Container smp-api Recreated 0.1s
Attaching to smp-api, smp-db
...
$ docker compose down -v
[+] Running 5/0
⠿ Container smp-api Removed 0.0s
⠿ Container smp-db Removed 0.0s
⠿ Volume smpapi_data Removed 0.0s
⠿ Volume smpdb_data Removed 0.0s
⠿ Network sqlmodel-pg-api_default Rem... 0.1s
참고: git
# 신규 리포지토리에 연결시
git init
git add --all
git commit -m "first commit"
git branch -M main
git remote add origin $GITHUB/maxmin93/fastapi-sqlmodel-heroes.git
git push -u origin main
# 기존 리포지토리에 연결시
git remote add origin https://github.com/maxmin93/fastapi-sqlmodel-heroes.git
git branch -M main
git push -u origin main
# 새로운 브랜치 생성/변경
git checkout -b db-mongo
# 새로운 브랜치로 push (최초)
git push --set-upstream origin db-mongo
# main 브랜치로 변경
git checkout main
# 변경사항 로그 조회
git log --graph --decorate --oneline
# 변경사항 파일 조회
git status -u
# 파일 변경사항 조회 (최신 HEAD와 비교)
git diff ../README.md
# staged 파일 변경사항 조회 (git add 된)
git diff --staged ../README.md
# 파일 변경사항 취소
git restore ../README.md
# 변경 스테이징
git add --all
# branch 반영에 대한 Pull request 처리 후, main 에서
# tag 생성 및 반영 (=> release 생성)
# - 또는 모든 tags 반영 : git push origin --tags
git tag -a v0.0.3 -m "add mongoDB and APIs with csv upload"
git push origin v0.0.3