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
그 중 하나인 다음에 눈이 갔다
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
여러가지 자료들을 찾아보면서 결론을 내린 결과
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)} 동화를 만들어줘."
그 외에 방법이 여러가지 있긴 하던데... 위에 첨부한 블로그에 설명 있긴하더라...
근데 뭔가 복잡해
나중에 필요할때 다시 볼일 있겠지.. 없어야하는데
'프로그래밍 > FastAPI' 카테고리의 다른 글
(Python) 분명히 패키지를 설치하고 FastAPI를 실행했는데 패키지를 찾지 못하는 에러 대처하기(ModuleNotFoundError) (0) | 2024.03.06 |
---|---|
frontend(vue.js)에서 FastAPI로 타입이 여러개 담긴 Formdata 보내기 (0) | 2023.05.14 |
FastAPI에서 front로 파일을 제공하는 방법 - static file serving, Fileresponse + vue.js에서 음성파일 재생하기 (0) | 2023.05.10 |
중요한 변수를 숨겨야할 때, 사용할 수 있는 환경변수(env)설정 (0) | 2023.04.17 |
python 프로그램 수행을 위한 FastAPI 백엔드 서버 구축하기 (0) | 2023.04.17 |