Home > Software engineering >  Cant send post request via Postman, 422 Unprocessable Entity in Fast API
Cant send post request via Postman, 422 Unprocessable Entity in Fast API

Time:05-11

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

enter image description here

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 ! :)

  • Related