front에서 데이터를 제대로 보냈는데 fastapi에서 422 unprocessable entity 에러 나는 경우

1. 422 unprocessable entity

 

front에서 axios로 back(fastapi)으로 데이터 요청을 보낼때, 볼 수 있는 에러

 

 

vue.js에서 title과 keyword를 text로 입력받고..

 

 //vue.js
 
 <b-form-group
        id="input-group-0"
        label="Review title"
        label-for="input-0"
      >
        <b-form-input
          id="input-0"
          v-model="form.title"
          type="text"
          placeholder="Enter title"
          required
        ></b-form-input>
      </b-form-group>

      <b-form-group
        id="input-group-1"
        label="Review Keyword"
        label-for="input-1"
      >
        <b-form-input
          id="input-1"
          v-model="form.keyword"
          type="text"
          placeholder="Enter Keyword"
          required
        ></b-form-input>
        <button @click="createAIReview">자동 작성</button>
      </b-form-group>

//중간 생략

async createAIReview () {
      axios
        .post(`http://127.0.0.1:8000/reviews/gpt`, {
          title: this.form.title,
          keyword: this.form.keyword,
          writer: this.form.writer,
          char: this.form.char
        })
        .then(result => {
          console.log(result)
          this.form.content = result.review
          this.form.score = result.star
        })
        .catch(err => {
          console.log(err)
        })
    },

 

fastapi에서 다음과 같은 함수에 요청을 보내는 형태..

 

#fastapi

"""
input: title, words
output: review, star point
"""
@app.post("/reviews/gpt")
async def create_review(title:str, words: str, writer=None, char=None):
    
    # {작가}의 {제목} 책을 읽고 {키워드}를 키워드로 해서 서평을 {char} 자 이내로 써줘.
    # message 구성
    if writer != None and char != None:
        
        #default number of character value
        char = max(100,int(char))

        m = f"너는 {writer}의 {title}이라는 책을 읽은 사람이야. 자기소개는 하지 말고 {words}를 키워드로 해서 서평을 {char}자 이내로 써줘"
    elif writer == None:
        
        #default number of character value
        if char == None:
            char = 100
        else:
            char = max(100,int(char))
        
        m = f"너는 {title}이라는 책을 읽은 사람이야. 자기소개는 하지 말고 {words}를 키워드로 해서 서평을 {char}자 이내로 써줘"
    
    elif char == None:
        
        m = f"너는 {writer}의 {title}이라는 책을 읽은 사람이야. 자기소개는 하지 말고 {words}를 키워드로 해서 서평을 100자 이내로 써줘"
    
    #chatgpt request
    completion = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": m}
    ]
    )
    
    #chatgpt response
    response = completion.choices[0].message['content']
    
    #predicted star point
    star = predict_star_point(response)
    
    return {"review":response, "star":star}

 

 

분명히 text로 입력받았으니 title과 words는 str인데..

 

혹시 text와 str은 다른가 해서.. console.log로 타입을 찍어보기도함

 

console.log(typeof this.form.title)
console.log(typeof this.form.keyword)
console.log(typeof this.form.writer)
console.log(typeof this.form.char)

 

기본값이 null인 writer와 char은 object로 되어있고.. text로 받아온 title과 keyword는 string으로

 

 

 

 

 

2. fastapi type hint

 

fastapi에서 type hint를 적을때... 적는 방법이 여러가지가 있더라고

 

javascript - Python: FastAPI error 422 with POST request when sending JSON data - Stack Overflow

 

Python: FastAPI error 422 with POST request when sending JSON data

I'm building a simple API to test a database. When I use GET request everything works fine, but if I change to POST, I get 422 Unprocessable Entity error. Here is the FastAPI code: from fastapi imp...

stackoverflow.com

 

그 중 하나인 다음에 눈이 갔다

 

from typing import Dict, Any

@app.post('/')
def main(user: Dict[Any, Any]):  # or, user: dict
    return user

 

그래서 fastapi에서도 비슷하게 바꿔봄

 

@app.post("/reviews/gpt")
async def create_review(title:Dict[Any,Any], words:Dict[Any,Any], writer:Dict[Any,Any]=None, char:Dict[Any,Any]=None):

 

근데 이래도 422 error 나더라고

 

근데 비슷하게 얘는 잘 동작했거든.. 그래서 될줄 알았는데

 

"""
input: story keyword
output: chatgpt story
"""
@app.post("/stories/gpt")
async def create_story(text:Dict[Any,Any]):
    
    #chatgpt query
    query = f"너는 동화작가야. 자기소개는 하지 말고 어린이를 위해서 {text['text']}로 {np.random.choice(ADJECTIVE)} 동화를 만들어줘."
        
    #chatgpt request
    completion = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": query}
    ]
    )
    
    #chatgpt response
    return {'data':completion.choices[0].message['content']}

 

None으로 받는 두 매개변수가 문제인가 해서 그것도 지워봤지만 여전히 에러나고

 

@app.post("/reviews/gpt")
async def create_review(title:Dict[Any,Any], words:Dict[Any,Any]):

 

front에서 keyword로 보내고 있고 fastapi에서는 words로 받고있는데 그것때문인가해서

 

변수명도 바꿔보고 했지만 될리 없고

 

 

https://velog.io/@kjh03160/Body-Multiple-Parameters

 

Fast API, Body - Multiple Parameters, Field

이제 모든 parameter들의 선언 방법에 대해 알아보았으니, 아래의 코드를 보며 어떤 parameter인지 보자.item_id : path parameter (required) → URL 에 명시q : query parameter (optional) → URL X,

velog.io

 

여러가지 자료들을 찾아보면서 결론을 내린 결과

 

1) parameter도 종류가 여러가지가 있음

 

query parameter가 있고 path parameter가 있고... 여러가지가 있더라고

 

근데 기본적으로 get요청은 query parameter 형식으로 url에 parameter 값을 넣어주고

 

post 요청은 json 형식으로 request body에 포함시켜서 요청을 하는데..

 

#fastapi

"""
input: title, words
output: review, star point
"""
@app.post("/reviews/gpt")
async def create_review(title:str, words: str, writer=None, char=None):

 

위와 같이 단일 변수 형태로 준다면 기본적으로 query parameter라서 get요청으로 보내야하는듯

 

post에 json 형태로 data를 보내고 있기 때문에 422 unprocessable error가 나는듯

 

2) post로 data보낼때, json 형식으로 준다면, fastapi에서 기본적으로 parameter를 하나만 받자

 

    async createAIReview () {
      axios
        .post(`http://127.0.0.1:8000/reviews/gpt`, {
          title: this.form.title,
          keyword: this.form.keyword,
          writer: this.form.writer,
          char: this.form.char
        })
        .then(result => {
          console.log(result)
          this.form.content = result.data.review
          this.form.score = result.data.star
        })
        .catch(err => {
          console.log(err)
        })
    },

 

위와 같이 axios를 구성하고, data를 title, keyword, writer, char 4개를 한번에 json으로 묶어서 보내줄때,

 

다음과 같이 data라는 매개변수 하나만 받고, 얘는 dict로 받으니까(json = dict)

 

일단 data로 받고 그 안에서 unpack시켜서 4개의 변수 title, words, writer, char... 형식으로 사용하자

 

이게 제일 마음 편하다..

 

"""
input: title, words
output: review, star point
"""
@app.post("/reviews/gpt")
async def create_review(data:Dict[Any,Any]):
    
    # {작가}의 {제목} 책을 읽고 {키워드}를 키워드로 해서 서평을 {char} 자 이내로 써줘.
    
    #unpack data
    title = data["title"]
    words = data["keyword"]
    writer = data["writer"]
    char = data["char"]

 

그렇다면 얘도 동작한 이유가 이해가 될듯

 

text가 json 형태로 들어와서, 그 안에서 실제 개별 변수 사용할때는 text['text']로 풀어서 써줘야하는..

 

"""
input: story keyword
output: chatgpt story
"""
@app.post("/stories/gpt")
async def create_story(text:Dict[Any,Any]):
    
    #chatgpt query
    query = f"너는 동화작가야. 자기소개는 하지 말고 어린이를 위해서 {text['text']}로 {np.random.choice(ADJECTIVE)} 동화를 만들어줘."

 

 

그 외에 방법이 여러가지 있긴 하던데... 위에 첨부한 블로그에 설명 있긴하더라...

 

근데 뭔가 복잡해

 

나중에 필요할때 다시 볼일 있겠지.. 없어야하는데

TAGS.

Comments