I am writing because I have a problem with fastAPI and postman. I have this post function
@router.post('/', status_code=status.HTTP_201_CREATED)
def create(request: schemas.Blog, db: Session = Depends(get_db), current_user: schemas.User = Depends(oauth2.get_current_user)):
request_user = db.query(models.User).filter(
models.User.email == current_user.email).first()
print(request_user)
new_blog = models.Blog(title=request.title,
body=request.body, user_id=request_user.id)
db.add(new_blog)
db.commit()
db.refresh(new_blog)
return new_blog
My models are:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, index=True)
username = Column(String, unique=True, index=True)
email = Column(String, unique=True, index=True)
password = Column(String, unique=False, index=True)
blogs = relationship('Blog', back_populates='creator')
class Blog(Base):
__tablename__ = 'blogs'
id = Column(Integer, primary_key=True, index=True)
title = Column(String, unique=True, index=True)
body = Column(String, unique=False, index=True)
user_id = Column(Integer, ForeignKey('users.id'))
creator = relationship('User', back_populates='blogs')
def __str__(self):
return self.title
And schemas
class Blog(BaseModel):
title: str
body: str
class Config:
orm_mode = True
So with this setup on my fastAPI docs everything works fine. I can create new blog but when I do exactly same thing in Postman I am getting 422 Unproccessed Entity error
Its really weird because I am doing exactly the same action but in Postman... Does anyone faced problem like this ?
CodePudding user response:
You're sending form data, not JSON which is what your endpoint expect. Change the setting in Postman: go to "Raw data" and select "JSON" in the pulldown (instead of text as it might as default) and enter the relevant JSON:
{
'title': 'foo',
'body': 'body'
}
I also recommend against using request
as the variable name for your submitted object, as this is usually used for values from FastAPI's built-in Request
object. Instead use blog_post
or something similar:
@router.post('/', status_code=status.HTTP_201_CREATED)
def create(blog_post: schemas.Blog, ...):
CodePudding user response:
!! EDIT !! Propably its working with forms because of OAuth2PasswordRequestForm but I will keep my question here for deeper explanation :)
I followed Instructions from MatsLindh and it works for now but I have one more question. I understand that my requested had to be in raw data. But I have a function to login and generate JWT token which is working with sending form data in postman. Can you explain me what is making my function acceptable with form data ? Here is function Iam using for login and generate tokens
@router.post('/')
def login(request: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(database.get_db)):
user = db.query(models.User).filter(
models.User.email == request.username).first()
if not user:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail='invalid credentials')
if not Hash.verify_password(request.password, user.password):
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail='invalid password')
# generate a jwt token and return
access_token_expires = timedelta(minutes=token.ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = token.create_access_token(
data={"sub": user.email}, expires_delta=access_token_expires)
And there is create_acces_token function
def create_access_token(data: dict, expires_delta):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() expires_delta
else:
expire = datetime.utcnow() timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
Also thank you for suggesting to change name of submitting object, I will change itd Thanks for answers guys ! :)