[英]Having Trouble Making a RESTful API with Flask-RestX: “No operations defined in spec!” and “404”s
In summary, I have been following the flask restx tutorials to make an api, however none of my endpoints appear on the swagger page ("No operations defined in spec!") and I just get 404 whenever I call them总之,我一直在关注flask restx教程来制作一个api,但是我的端点都没有出现在swagger页面上(“规范中没有定义操作!”),每当我调用它们时我都会得到404
I created my api mainly following this https://flask-restx.readthedocs.io/en/latest/scaling.html我主要按照这个https://flask-restx.readthedocs.io/en/latest/scaling.html创建了我的 api
I'm using python 3.8.3 for reference.我正在使用 python 3.8.3 作为参考。
A cut down example of what I'm doing is as follows.我正在做的一个简化的例子如下。
My question in short is, what am I missing?简而言之,我的问题是,我错过了什么? Currently drawing blank on why this doesn't work.目前尚不清楚为什么这不起作用。
project/
- __init__.py
- views/
- __init__.py
- test.py
manage.py
requirements.txt
requirements.txt要求.txt
Flask-RESTX==0.2.0
Flask-Script==2.0.6
manage.py管理文件
from flask_script import Manager
from project import app
manager = Manager(app)
if __name__ == '__main__':
manager.run()
project/ init .py项目/初始化.py
from flask import Flask
from project.views import api
app = Flask(__name__)
api.init_app(app)
project/views/ init .py项目/视图/初始化.py
from flask_restx import Api, Namespace, fields
api = Api(
title='TEST API',
version='1.0',
description='Testing Flask-RestX API.'
)
# Namespaces
ns_test = Namespace('test', description='a test namespace')
# Models
custom_greeting_model = ns_test.model('Custom', {
'greeting': fields.String(required=True),
})
# Add namespaces
api.add_namespace(ns_test)
project/views/test.py项目/视图/test.py
from flask_restx import Resource
from project.views import ns_test, custom_greeting_model
custom_greetings = list()
@ns_test.route('/')
class Hello(Resource):
@ns_test.doc('say_hello')
def get(self):
return 'hello', 200
@ns_test.route('/custom')
class Custom(Resource):
@ns_test.doc('custom_hello')
@ns_test.expect(custom_greeting_model)
@ns_test.marshal_with(custom_greeting_model)
def post(self, **kwargs):
custom_greetings.append(greeting)
pos = len(custom_greetings) - 1
return [{'id': pos, 'greeting': greeting}], 200
So going to the swagger page, I expect the 2 endpoints defined to be there, but I just see the aforementioned error.所以转到 swagger 页面,我希望定义的 2 个端点在那里,但我只看到上述错误。
Just using Ipython in a shell, I've tried to following calls using requests and just get back 404s.只是在 shell 中使用 Ipython,我尝试使用请求跟踪调用并返回 404。
import json
import requests as r
base_url = 'http://127.0.0.1:5000/'
response = r.get(base_url + 'api/test')
response
response = r.get(base_url + 'api/test/')
response
data = json.dumps({'greeting': 'hi'})
response = r.post(base_url + 'test/custom', data=data)
response
data = json.dumps({'greeting': 'hi'})
response = r.post(base_url + 'test/custom/', data=data)
response
I made a few mistakes in my code and test:我在代码和测试中犯了一些错误:
post
method.对如何将参数传递给post
方法做出一个奇怪的假设。expect
decorator在expect
装饰器中使用模型而不是请求解析器api/
prefix.在我的测试中使用错误的api/
前缀调用端点。I believe it's because I registered the namespace on the api before declaring any routes.我相信这是因为我在声明任何路由之前在 api 上注册了命名空间。
My understanding is when the api is registered on the app, the swagger documentation and routes on the app are setup at that point.我的理解是,当 api 在应用程序上注册时,应用程序上的 swagger 文档和路由就在那时设置。 Thus any routes defined on the api after this are not recognised.因此,在此之后在 api 上定义的任何路由都不会被识别。 I think this because when I declared the namespace in the views/test.py
file (also the model to avoid circular referencing between this file and views/__init__.py
), the swagger documentation had the routes defined and my tests worked (after I corrected them).我认为这是因为当我在views/test.py
文件(也是避免此文件和views/__init__.py
之间循环引用的模型)中声明命名空间时,swagger 文档定义了路由并且我的测试工作(在我之后纠正他们)。
There were some more mistakes in my app and my tests, which were我的应用程序和测试中还有一些错误,它们是
In my app, in the views/test.py
file, I made a silly assumption that a variable would be made of the expected parameter (that I would just magically have greeting as some non-local variable).在我的应用程序中,在views/test.py
文件中,我做了一个愚蠢的假设,即一个变量将由预期的参数组成(我只是神奇地将greeting作为一些非局部变量)。 Looking at the documentation, I learnt about the RequestParser , and that I needed to declare one like so查看文档,我了解了RequestParser ,并且我需要像这样声明一个
from flask_restx import reqparse
# Parser
custom_greeting_parser = reqparse.RequestParser()
custom_greeting_parser.add_argument('greeting', required=True, location='json')
and use this in the expect
decorator.并在expect
装饰器中使用它。 I could then retrieve a dictionary of the parameters in my post
method.然后我可以在我的post
方法中检索参数的字典。 with the below与下面
...
def post(self):
args = custom_greeting_parser.parse_args()
greeting = args['greeting']
...
The **kwargs
turned out to be unnecessary.事实证明**kwargs
是不必要的。
In my tests, I was calling the endpoint api/test
, which was incorrect, it was just test
.在我的测试中,我正在调用端点api/test
,这是不正确的,它只是test
。 The corrected test for this endpoint is此端点的更正测试是
Corrected test for test
endpoint更正test
端点的test
import json
import requests as r
base_url = 'http://127.0.0.1:5000/'
response = r.get(base_url + 'test')
print(response)
print(json.loads(response.content.decode()))
The test for the other endpoint, the post, I needed to include a header declaring the content type so that the parser would "see" the parameters, because I had specified the location explictily as json.对于另一个端点的测试,post,我需要包含一个声明内容类型的标头,以便解析器可以“看到”参数,因为我已经明确地将位置指定为 json。 Corrected test below.下面更正测试。
Corrected test for test/custom
endpoint更正测试test/custom
端点的test/custom
import json
import requests as r
base_url = 'http://127.0.0.1:5000/'
data = json.dumps({'greeting': 'hi'})
headers = {'content-type': 'application/json'}
response = r.post(base_url + 'test/custom', data=data, headers=headers)
print(response)
print(json.loads(response.content.decode()))
For the files with incorrect code.对于代码不正确的文件。
views/ init .py视图/初始化.py
from flask_restx import Api
from project.views.test import ns_test
api = Api(
title='TEST API',
version='1.0',
description='Testing Flask-RestX API.'
)
# Add namespaces
api.add_namespace(ns_test)
views/test.py视图/test.py
from flask_restx import Resource, Namespace, fields, reqparse
# Namespace
ns_test = Namespace('test', description='a test namespace')
# Models
custom_greeting_model = ns_test.model('Custom', {
'greeting': fields.String(required=True),
'id': fields.Integer(required=True),
})
# Parser
custom_greeting_parser = reqparse.RequestParser()
custom_greeting_parser.add_argument('greeting', required=True, location='json')
custom_greetings = list()
@ns_test.route('/')
class Hello(Resource):
@ns_test.doc('say_hello')
def get(self):
return 'hello', 200
@ns_test.route('/custom')
class Custom(Resource):
@ns_test.doc('custom_hello')
@ns_test.expect(custom_greeting_parser)
@ns_test.marshal_with(custom_greeting_model)
def post(self):
args = custom_greeting_parser.parse_args()
greeting = args['greeting']
custom_greetings.append(greeting)
pos = len(custom_greetings) - 1
return [{'id': pos, 'greeting': greeting}], 200
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.