FastAPI+React+DockerでQiitaみたいなサイトを作ってみたい -2日目-

# 目次
- [1日目 - 初期構成](https://qiita.com/ikeikeda/items/eeed5abb2230bf031ba5)

# 2日目 - /docsの作成
### API構成からDocsを作る
昨日はHelloWorldの出力止まりだったので、ここでQiitaっぽいサイトを作るときのAPI構成を考える。

モデル

- User
- Post
- Lgtm

一旦このくらいあればいいかな。
んでそれぞれのDBのリレーションを作る
![スクリーンショット 2021-12-22 18.36.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328944/1390abc7-00f3-d74d-1dde-c9e5a97c5d6e.png)


本当はもっといろいろ詰め込まないといけないんだけど、色々やりすぎると時間かかりすぎるので。
でAPI構成は一旦こんな感じ。

```
- User
POST /users
GET  /user/{user_id} 

- Post
GET    /posts
POST   /posts
GGET   /post/{post_id}
POST   /post/{post_id}/lgtm
DELETE /post/{post_id}/lgtm
```

# ルーターの設定
api/v1下にroutersのディレクトリを作成し、各ルーティング種別ごとにファイルを作る

```python:api/v1/routers/user.py
from fastapi import APIRouter

router = APIRouter()

@router.post('/users')
def create_user():
  pass

@router.get('/user/{user_id}')
def get_user():
  pass
```
```python:api/v1/routers/post.py
from fastapi import APIRouter

router = APIRouter()

@router.get('/posts')
def get_posts():
  pass

@router.post('/posts')
def create_post():
  pass

@router.get('/post/{post_id}')
def get_post():
  pass

@router.post('/post/{post_id}/lgtm')
def add_lgtm():
  pass

@router.delete('/post/{post_id}/lgtm')
def delete_lgtm():
  pass
```

でmain.pyのでこのrouterを読み込む

```python:api/v1/main.py
from fastapi import FastAPI

from api.v1.routers import user,post

app = FastAPI()

app.include_router(user.router)
app.include_router(post.router)
```

これでルーティングだけは反映されている。
docker-compose up してlocalhost:8000/docにアクセスするとルーティング情報（中身はなんもない）が表示される。
![スクリーンショット 2021-12-22 19.26.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328944/5126e3f3-61db-3e50-6812-57f1f6c985b2.png)


きっと実務ではAPIの仕様を固めれば、サーバーサイドとフロントエンドで構築をそれぞれ始めることができると思うので、それぞれの仕様まで作っておく。

FastAPIではschemaとしてそれぞれのルーティングにIO情報を設定しておくことで先程のDocsで仕様を確認できるらしい。

なのでapi/vi/schemasディレクトリを作成し、それぞれのschema情報を設定。

```python:api/v1/schemas/user.py
from pydantic import BaseModel, Field

class UserBase(BaseModel):
  login_id: str = Field(None, description="ログインID")
  name: str = Field(None, description="表示名")
  description: str = Field(None, description="プロフィール文")

class User(UserBase):
  id: int

class UserCreateRequest(UserBase):
  password: str = Field(None, description="パスワード")
```
```python:api/v1/schemas/post.py
from pydantic import BaseModel, Field

import api.v1.schemas.user as user_schema

class PostBase(BaseModel):
  title: str = Field(None, description="投稿タイトル")
  context: str = Field(None, description="投稿本文")

class Post(PostBase):
  id: int
  user: user_schema.User = Field(None, description="投稿ユーザー情報")
  lgtm＿count: int = Field(0, description="LGTM数")

class PostCreateRequest(PostBase):
  user_id: int = Field(None, description="ユーザーID")
```
これをそれぞれのrouterに記述していく

```python:api.v1.routers.user.py
from fastapi import APIRouter

import api.v1.schemas.user as user_schema

router = APIRouter()

@router.post('/users',response_model=user_schema.User)
def create_user(user:user_schema.UserCreateRequest):
  pass

@router.get('/user/{user_id}',response_model=user_schema.User)
def get_user():
  pass
```
```python:api.v1.routers.post.py
from fastapi import APIRouter
from typing import List

import api.v1.schemas.post as post_schema

router = APIRouter()

@router.get('/posts',response_model=List[post_schema.Post])
def get_posts():
  pass

@router.post('/posts',response_model=post_schema.Post)
def create_post(post:post_schema.PostCreateRequest):
  pass

@router.get('/post/{post_id}',response_model=post_schema.Post)
def get_post():
  pass

@router.post('/post/{post_id}/lgtm',response_model=post_schema.Post)
def add_lgtm():
  pass

@router.delete('/post/{post_id}/lgtm',response_model=post_schema.Post)
def delete_lgtm():
  pass
```
本当はLGTMとかのレスポンスはLGTM数とかだけでいいのかもだけど一旦はこの構築にしておく。

ここまで書くとdocsがいい感じになる
![スクリーンショット 2021-12-22 20.09.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328944/ced33b99-7842-3491-14a2-0ae4919c09b7.png)

これをもとにサーバーサイドとフロントサイドでそれぞれ開発を行えそう。
便利だなぁ。

後々色々付け足すかもしれないけど、一旦はここまで。