pythonflaskflask-restfulflask-jwt-extendedflask-restx

Using Flask-JWT-Extended with Flask-restx


I'm building an API using Flask-restx, I'm using a token system for authentication, I'm using Flask-JWT-Extended, in my case I managed to get the token, but I'm having trouble putting it in views, I'm using a decorator

@jwt_required decorator on views like this

class InputReaderView(Resource):
    @jwt_required
    def post(self):
        username = get_jwt_identity()
        input_reader = reqparse.RequestParser()
        input_reader.add_argument("type", type=str, required=True)
        input_reader.add_argument("data", type=dict, action="append", required=True)
        args = input_reader.parse_args()

        # datas = populate(os.path.join(BaseConfig.UPLOAD_FOLDER, 'f1040s1-tagged.json'), args['data'])
        pdf_path = os.path.join(BaseConfig.UPLOAD_FOLDER, "pdf")

        for pdf in os.listdir(pdf_path):
            filename = secure_filename(pdf)
            if filename == args["type"]:
                pdf_path = os.path.join(pdf_path, filename)
                datas = populate(
                    os.path.join(BaseConfig.UPLOAD_FOLDER, "f1040s1-tagged.json"),
                    args["data"],
                )
                validated: dict = {}
                fields = extract_field(pdf_path=pdf_path)
                for fv in fields:
                    for data in datas:
                        if fv["FieldName"] == data["form"]:
                            validated[fv["FieldName"]] = data["value"]

                filled_pdf = pypdftk.fill_form(
                    pdf_path,
                    datas=validated,
                    out_file="{}/{}-filled.pdf".format(
                        os.path.join(BaseConfig.UPLOAD_FOLDER, "filled"),
                        filename.replace(".pdf", ""),
                    ),
                )

                return jsonify(
                {
                    "title": f"{filename}",
                    "filled pdf download_url": "{}{}".format(
                        "http://localhost:5000",
                        url_for(
                            "api.download_filled_pdf",
                            download_url="{}-filled.pdf".format(
                                filename.replace(".pdf", "")
                            ),
                        )
                        .title()
                        .lower(),
                    ),
                }
            )

and this is my configuration using flask-JWT-Extended on my app

# core/__init__.py
def create_app():
    # import models
    from apps.dashboard.models import Users
    
    
    # app = Flask(f'{DemoActor.__name__}Service')
    app = Flask(__name__)
    app.config.from_object('core.config.ProductionConfig')
    login_manager.init_app(app)
    login_manager.login_view = 'api.login_view'
    
    db.init_app(app)
    migrate.init_app(app=app, db=db)
    jwt.init_app(app)
    
    
    # register new blueprint
    app.register_blueprint(api_blueprint)
    
    # flask context
    @app.shell_context_processor
    def ctx():
        return {'app':app, 'db':db}

    
    return app
# core/initial.py
"""
initialize project
"""

from flask_jwt_extended import JWTManager
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

login_manager = LoginManager()
migrate = Migrate()
db = SQLAlchemy()
jwt = JWTManager()

but I got this error

127.0.0.1 - - [14/Jul/2022 17:18:17] "POST /input-reader HTTP/1.1" 500 -
Traceback (most recent call last):
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask\app.py", line 2095, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask\app.py", line 2080, in wsgi_app
    response = self.handle_exception(e)
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask_restx\api.py", line 671, in error_router
    return original_handler(f)
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask_restx\api.py", line 669, in error_router
    return self.handle_error(e)
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask\app.py", line 2077, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask\app.py", line 1525, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask_restx\api.py", line 671, in error_router
    return original_handler(f)
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask_restx\api.py", line 669, in error_router
    return self.handle_error(e)
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask\app.py", line 1523, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask\app.py", line 1509, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask_restx\api.py", line 407, in wrapper
    return self.make_response(data, code, headers=headers)
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask_restx\api.py", line 430, in make_response
    resp = self.representations[mediatype](data, *args, **kwargs)
  File "C:\Users\feril\Documents\Code\JOB\pallo_project\flask-dapr\venv\lib\site-packages\flask_restx\representations.py", line 25, in output_json
    dumped = dumps(data, **settings) + "\n"
  File "C:\src\python\lib\json\__init__.py", line 234, in dumps
    return cls(
  File "C:\src\python\lib\json\encoder.py", line 201, in encode
    chunks = list(chunks)
  File "C:\src\python\lib\json\encoder.py", line 438, in _iterencode
    o = _default(o)
  File "C:\src\python\lib\json\encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type function is not JSON serializable

anyone know why this? or there is an example of using Flask-JWT-Extended with Flask-Restx?, can it be solved?


Solution

  • jwt_required should be called as followed (you're missing the brackets ()):

    class InputReaderView(Resource):
        @jwt_required()
        def post(self):
    

    You can also use @jwt_required(optional=True) which will work regardless if a token is provided or not.

    References