MJSEC 활동/백엔드(2025-2학기)

백엔드 4주차 / 질문 목록 화면, 답변 등록 구현

stw0218 2025. 11. 6.

https://github.com/pahkey/fastapi-book/tree/v2.07

 

GitHub - pahkey/fastapi-book

Contribute to pahkey/fastapi-book development by creating an account on GitHub.

github.com

 

점프 투 fastapi의 2-07 장 까지 진행했다.

 

 

책에는 "content: 빈 값은 허용되지 않습니다."

라고 나오는데 파이썬 버젼의 차이인지 앞에 "Value error," 가 붙어서 나왔다.

 

 

 

 

# answer_crud.py
from datetime import datetime
from sqlalchemy.orm import Session

from domain.answer.answer_schema import AnswerCreate
from models import Answer, Question

def create_answer(db: Session, question: Question, answer_create: AnswerCreate):
    db_answer = Answer(question=question,
                          content=answer_create.content,
                            create_date=datetime.now())
    db.add(db_answer)
    db.commit()
# answer_router.py
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from starlette import status

from database import get_db
from domain.answer import answer_schema, answer_crud
from domain.question import question_crud

router = APIRouter(
    prefix="/api/answer",
)

@router.post("/create/{question_id}", status_code=status.HTTP_204_NO_CONTENT)
def answer_create(question_id: int,
                  _answer_create: answer_schema.AnswerCreate,
                  db: Session = Depends(get_db)):

    # create answer
    question = question_crud.get_question(db, question_id=question_id)

    if not question:
        raise HTTPException(status_code=404, detail="Question not found")
    answer_crud.create_answer(db, question=question, answer_create=_answer_create)
# answer_schema.py
import datetime
from pydantic import BaseModel, field_validator

class AnswerCreate(BaseModel):
    content: str

    @field_validator('content')
    def not_empty(cls, v):
        if not v or not v.strip():
            raise ValueError('빈 값은 허용되지 않습니다.')
        return v
    
class Answer(BaseModel):
    id: int
    content: str
    create_date: datetime.datetime
<script>
    // Error.svelte
    export let error // 전달받은 오류
</script>

{#if typeof error.detail === 'string'}
    <ul>
        <li>{error.detail}</li>
    </ul>
{:else if typeof error.detail === 'object' && error.detail.length > 0}
    <ul>
        {#each error.detail as err, i}
        <li>
            <strong>{err.loc[1]}</strong> : {err.msg}
        </li>
        {/each}
    </ul>
{/if}
<script>
    // Detail.svelte
    import fastapi from "../lib/api"
    import Error from "../components/Error.svelte"

    export let params = {}
    let question_id = params.question_id
    let question = {answers:[]}
    let content = ""
    let error = {detail:[]}

    function get_question() {
        fastapi("get", "/api/question/detail/" + question_id, {}, (json) => {
            question = json
        })
    }

    get_question()

    function post_answer(event) {
        event.preventDefault()
        let url = "/api/answer/create/" + question_id
        let params = {
            content: content,
        }
        fastapi("post", url, params, (json) => {
            content = ""
            error = {detail:[]}
            get_question()
        }, (err_json) => {
            error = err_json
        })
    }
</script>

<h1>{question.subject}</h1>
<div>
    {question.content}
</div>
<ul>
    {#each question.answers as answer}
        <li>{answer.content}</li>
    {/each}
</ul>
<Error error={error} />
<form method="post">
    <textarea rows="15" bind:value={content}></textarea>
    <input type="submit" value="답변등록" on:click="{post_answer}">
</form>

 

svelte로 question 및 answer 화면 구현 하는 게 주를 이뤘다.

 

fastapi도 가독성 좋고 편리하다고 느꼈는데

frontend framework인 svelte도 문법적으로 깔끔해보인다.

댓글