Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The function either returned None or ended without a return statement while using with flask_restful #62

Closed
paurakhsharma opened this issue Jul 10, 2020 · 12 comments

Comments

@paurakhsharma
Copy link

paurakhsharma commented Jul 10, 2020

flask_restful supports returning None from the view function, but I am getting error this error when I use metrics for endpoint.

e.g

from flask_restful import Resource

by_path_counter = metrics.counter(
    'by_path_counter', 'Request count by request paths',
    labels={'path': lambda: request.path}
)

class FoodApi(Resource):
    @by_path_counter
    def post(self):
        create_food()
        return None, 200

It works fine if I don't use @by_path_counter decorator, and returns null in the response.

But when I add the decorator, I get this error.

Traceback (most recent call last):
  File "/home/wartner/.local/share/virtualenvs/config_service-TDer8cy_/lib/python3.8/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/wartner/.local/share/virtualenvs/config_service-TDer8cy_/lib/python3.8/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/wartner/.local/share/virtualenvs/config_service-TDer8cy_/lib/python3.8/site-packages/flask_restful/__init__.py", line 468, in wrapper
    resp = resource(*args, **kwargs)
  File "/home/wartner/.local/share/virtualenvs/config_service-TDer8cy_/lib/python3.8/site-packages/flask/views.py", line 89, in view
    return self.dispatch_request(*args, **kwargs)
  File "/home/wartner/.local/share/virtualenvs/config_service-TDer8cy_/lib/python3.8/site-packages/flask_restful/__init__.py", line 583, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/home/wartner/.local/share/virtualenvs/config_service-TDer8cy_/lib/python3.8/site-packages/prometheus_flask_exporter/__init__.py", line 633, in func
    response = make_response(response)
  File "/home/wartner/.local/share/virtualenvs/config_service-TDer8cy_/lib/python3.8/site-packages/flask/helpers.py", line 223, in make_response
    return current_app.make_response(args)
  File "/home/wartner/.local/share/virtualenvs/config_service-TDer8cy_/lib/python3.8/site-packages/flask/app.py", line 2097, in make_response
    raise TypeError(
TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.

Is there any way, I can work around this? (I have to return None)

Any kind of help will be highly appreciated, thank you 🙂

Note: It works fine on other view functions where I return not None values

@paurakhsharma
Copy link
Author

I am using prometheus-flask-exporter version 0.14.1

@rycus86
Copy link
Owner

rycus86 commented Jul 10, 2020

Thanks for the report! I'll have a look, sounds like a bug potentially.

@paurakhsharma
Copy link
Author

Thank you for the quick reply 🙂

@rycus86
Copy link
Owner

rycus86 commented Jul 10, 2020

If you switch to RESTfulPrometheusMetrics in the new 0.15.0 version, this should now work out of the box.

@paurakhsharma
Copy link
Author

@rycus86 thank you so much, this does solve the problem.
But I have one problem I need to implement application factory method because of circular dependency issue,

Previously I used to do

metrics = PrometheusMetrics.for_app_factory()
# and later
metrics.init_app(app)

Any tip on how I can achieve something similar while using RESTfulPrometheusMetrics

@rycus86
Copy link
Owner

rycus86 commented Jul 13, 2020

That might need some changes to support it nicely. 🤔
Until then, you should be able to use it like this:

metrics = RESTfulPrometheusMetrics(app=None, api=api)
# and later
metrics.init_app(app)
@rycus86
Copy link
Owner

rycus86 commented Jul 22, 2020

Started building a new 0.15.1 release, in that you can do it like this:

metrics = RESTfulPrometheusMetrics.for_app_factory(api)
# and later
metrics.init_app(app)
@paurakhsharma
Copy link
Author

This looks great, is it possible we pass api later as well?
like,

metrics = RESTfulPrometheusMetrics.for_app_factory()
# and later
metrics.init_app(app, api)
@rycus86
Copy link
Owner

rycus86 commented Jul 22, 2020

Yeah, good point!
In 0.15.4 you'll be able to do:

app = Flask(__name__)
restful_api = Api(app)

metrics = RESTfulPrometheusMetrics.for_app_factory()
# and later
metrics.init_app(app, restful_api)
@paurakhsharma
Copy link
Author

You are just awesome. Thank you so much this helps me a lot ☺️

@Curiouspaul1
Copy link

Hi @rycus86 thanks for all your effort, i have one small question about this. Which do i use between GunicornPrometheusMetrics and RESTfulPrometheusMetrics for when I'm using both gunicorn and Flask-restX

@rycus86
Copy link
Owner

rycus86 commented Oct 15, 2022

Good question @Curiouspaul1 , not sure if we have an exact test for that yet.
Have you tried either way? If so, did it behave as you needed it?
If it doesn't work, perhaps a sample app & setup might be good then we can test how the metrics setup composition should look like there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants