python-restx / flask-restx

Fork of Flask-RESTPlus: Fully featured framework for fast, easy and documented API development with Flask
https://flask-restx.readthedocs.io/en/latest/
Other
2.16k stars 335 forks source link

How to programmatically define the swagger docstring of an endpoint without explicitly typing it in the function docstring? #498

Closed svein-izy closed 1 year ago

svein-izy commented 1 year ago

I have the following endpoint:

@api.route('/users')
class RootUsers(Resource):
    @jwt_required()
    @api.expect(token_args)
    @api.response(200, 'Success')
    @api.response(500, 'Error')
    def get(self):
        """ Get all users """
        return get_all_users()

Which in swagger results in the following: image

Lets call the part in swagger that says "Get all users" for endpoint docstring.

Now, any attempt to alter the function docstring "Get all users" (for example with f""" Get all users - {var}""") results in the the following swagger result: image

The endpoint docstring simpy disappears.

This is my question: Is there any way I can define the endpoint docstring (for example as an argument to the def get(self) function) so that it renders correctly in swagger?

peter-doggart commented 1 year ago

@svein-izy Can I ask what the use case for doing this is?

svein-izy commented 1 year ago

@peter-doggart My endpoints are defined with an endpoint ID. This endpoint ID is used both for identifying the endpoint quickly in swagger, and as a part of an endpoint access system. This implies that I need the ID both programmatically for running the access check, and hard typed for displaying it in swagger. Right now I have to type the endpoint ID twice, which has led to some endpoints having differing endpoint ID between access check and swagger docstring. This would be solved by just having to enter the ID once for the access check, and then using the same variable in the docstring.

peter-doggart commented 1 year ago

Just having a look, python requires docstrings to be string literals only. The docs for f-strings also mention they can't be used for docstrings.

However, I assume you can probably still hijack the obj.__doc__ string with a decorator. I'm not near my flask-restx computer to test, but I assume you could do something like:

def generate_docstring(var):
    def inner(obj):
        obj.__doc__ = """
            Get all users - {var}
            """.format(var=var)
        return obj
    return inner

@api.route('/users')
class RootUsers(Resource):
    insert_string = "TEST"
    @jwt_required()
    @api.expect(token_args)
    @api.response(200, 'Success')
    @api.response(500, 'Error')
    @generate_docstring(insert_string)
    def get(self):
        return get_all_users()

Does that work?

svein-izy commented 1 year ago

@peter-doggart It works, thanks! :)