TypeError: Object of type function is not JSON serializable when using flask_jwt_extended int RESTful API
Asked Answered
A

2

16

I'm building a REST API using flask. I'm using postman for testing a route that creates a new item in my database, but only if the user is logged in. The routes for registering and login are working well, the last one returns the token using flask_jwt_extended module. When I send a post request to my "/api/notes" (creates a new note in database) I get the error bellow:

" (...) raise TypeError(f'Object of type {o.class.name} '

TypeError: Object of type function is not JSON serializable"

for the request I'm using the authorization tab of postman. type: Bearer Token, and my token in the field (tried with and without quotation marks)

I had faced this error this morning, before implementing my one-many relantionship, but I got it working by replacing my VERY_LONG_TOKEN with "VERY_LONG_TOKEN" in the Barear token field. I thought that because the token includes dots, it was interpreting as a function. But after implementing the relationship, I went to test and got this error again.

my note.py file:

from flask import request, Response, jsonify
from app.models import User, Note
from flask_restful import Resource
from flask_jwt_extended import jwt_required, get_jwt_identity

class NotesApi(Resource):
    def get(self):
        notes = Note.objects().to_json()
        return Response(notes, mimetype="application/json", status=200)

    @jwt_required  
    def post(self):  # post method I'm making a request for
        print("fool")  # this doesn't get printed  ->  not reaching 
        user_id = get_jwt_identity()
        data = request.get_json(force=True)
        if data:
            user = User.objects(id=user_id) # logged in user
            note = Note(**data, user_author=user) # creates note with the author
            note.save()
            user.update(push__notes=note) # add this note to users notes
            user.save()
            id = str(note.id)
            return {'id': id}, 200
        else:
            return {'error': 'missing data'}, 400

my models.py:

from app import db  # using mongodb
from datetime import datetime
from flask_bcrypt import generate_password_hash, check_password_hash

class Note(db.Document):
    title = db.StringField(max_length=120,required=True)
    content = db.StringField(required=True)
    status = db.BooleanField(required=True, default=False)
    date_modified = db.DateTimeField(default=datetime.utcnow)
    user_author = db.ReferenceField('User')
    
class User(db.Document):
    username = db.StringField(max_length=100, required=True, unique=True)
    email = db.StringField(max_length=120, required=True, unique=True)
    password = db.StringField(required=True)
    remember_me = db.BooleanField(default=False)
    notes = db.ListField(db.ReferenceField('Note', reverse_delete_rule=db.PULL)) # one-many relationship

    def hash_password(self):
        self.password = generate_password_hash(self.password).decode('utf8')

    def check_password(self, password):
        return check_password_hash(self.password, password)


User.register_delete_rule(Note, 'user_author', db.CASCADE)

init.py:

from flask import Flask
from config import Config  # my config class to set MONGOBD_HOST and SECRET_CLASS
from flask_mongoengine import MongoEngine
from flask_restful import Api
from flask_bcrypt import Bcrypt
from flask_jwt_extended import JWTManager

app = Flask(__name__)
app.config.from_object(Config)
db = MongoEngine(app)
api = Api(app)
bcrypt = Bcrypt(app)
jwt = JWTManager(app)

from app.resources.routes import initialize_routes
initialize_routes(api) 

resources/routes.py:

from .note import NotesApi, NoteApi
from .auth import SignupApi, LoginApi

def initialize_routes(api):
    api.add_resource(NotesApi, '/api/notes')
    api.add_resource(NoteApi, '/api/note/<id>')
    api.add_resource(SignupApi, '/api/auth/signup')
    api.add_resource(LoginApi, '/api/auth/login')

folder structure:

app
  |_ resources
      |_ auth.py  # signup working well, login also working, return a token (type = String)
      |_ note.py
      |_ routes.py
  |_ __init__.py
  |_ models.py
config.py
appname.py  #just import app and do a app.run()

body of my post request:

{
   "title": "test0",
   "content": "test0"  
}

Did anyone faced it before or know how to solve it?

Edit: added more code info

Aldercy answered 14/2, 2021 at 21:5 Comment(4)
Can you provide a minimal reproducible example please? As a new user here, please also take the tour and read How to Ask.Mopup
Sorry, I edited my question adding more information. Thank you.Aldercy
@WilianeSouza Where the app breaks at note.py file?Marchetti
It wasn't pointing any line of my code in the traceback, but I fixed the issue based on Maylor's answer. Thank you.Aldercy
R
34

Looks like flask-jwt-extended released a new version over the weekend. As part of the API changes, the @jwt_required decorator is now @jwt_required()

https://flask-jwt-extended.readthedocs.io/en/stable/v4_upgrade_guide.html#api-changes

Ruhnke answered 15/2, 2021 at 9:2 Comment(3)
not sure why have you mentioned "jtw" instead of "jwt"Kylix
Thanks, this is the solution. IDE does not recognize sythax change in jwt extended.Malik
Man, Thank you soo much.. I have been busting my .... you got the idea, I didn't knew that it was due to '()'.. Thanks..Pusillanimity
A
0

Just get rid of the HTTP status codes, that worked for me. example

Replace:

return {'id': id}, 200

with:

return {'id': id}

or:

resp = jsonify({'id': id})

resp.status_code = 200

return resp
Andrew answered 26/10, 2021 at 9:43 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Lycanthrope

© 2022 - 2024 — McMap. All rights reserved.