I am getting AttributeError: module 'flask_restx.api' has no attribute 'doc' when it try add additional for API when using flask restx. How this error can be fixed.
api.py
from flask import Flask
from flask_restx import Api, Resource
from hello import Hello
app = Flask(__name__)
api = Api(app)
api.add_resource(Hello, '/hello')
if __name__ == '__main__':
app.run(debug=True)
hello.py
from flask_restx import Resource, api
@api.doc(params={'id': 'An ID'})
class Hello(Resource):
def get(self):
return {
'data': {
'names': ['one',
'two',
'three']
}
}
I don't know which tutorial you followed (if you followed any), but the
@api.doc(params={'id': 'An ID'})
needs an instance of Api class and not flask-restx.api
Usually, in tutorials (at least the ones I found), they show how to do all of that in the same file. So your code would work if it was written like so :
api.py
from flask import Flask
from flask_restx import Api, Resource
from hello import Hello
app = Flask(__name__)
api = Api(app)
@api.doc(params={'id': 'An ID'})
class Hello(Resource):
def get(self):
return {
'data': {
'names': ['one',
'two',
'three']
}
}
api.add_resource(Hello, '/hello')
if __name__ == '__main__':
app.run(debug=True)
Now, this is not what you want to achieve, as I guess you would like to split the file to have some structure (as I would like to as well). Awfully, I couldn't find a proper tutorial for that online, but here is what I did in my project (using your example code):
api > __init__.py
from flask_restx import Namespace
default_namespace = Namespace("default", ordered=True)
api > hello.py
from flask_restx import Resource
from api import default_namespace as ns
@ns.doc(params={'id': 'An ID'})
class Hello(Resource):
def get(self):
return {
'data': {
'names': ['one',
'two',
'three']
}
}
app.py (your api.py file) located at root
from flask import Flask
from flask_restx import Api
from hello import Hello
from api import default_namespace
app = Flask(__name__)
api = Api(app)
api.add_resource(Hello, '/hello')
api.add_namespace(default_namespace)
if __name__ == '__main__':
app.run(debug=True)
Where the package structure is:
.
+-- app.py
+-- api
+-- __init__.py
+-- hello.py
By declaring a namespace, you can actually group Resources together in Swagger. And the reason why I put the namespace in another file (here __init__.py
) is to not have a circular import.
And you can use all decorators with ns.doc, ns.route, ... as you could with the api. (where api is a variable ;) ).
Btw, the ns is an Alias, if you prefer to put something else, it is up to you to change it in the import statement.
Note that this might not be the best way, but it is clean enough for me and the structure I have. If someone with more experience knows how to do this differently, please reply ;)