I want to be able to define more or less arbitrary changes in functions decorated with @app.route that may only be run by a non-production server. A straight forward way to implement what I mean would be to put the dev-only changes into if-blocks that check the current environment:
import flask
app = flask.Flask(__name__)
@app.route('/check', methods=['POST'])
def check():
"""Performs some kind of check on the given request data."""
# this if-block gates the dev/test/review-only behavior
if app.config['ENV'] != 'production':
# let a tester short-circuit the logic if they want
if flask.request.json['payload'] == 'just give me an ok':
return flask.jsonify('ok')
# the only code that runs in production, or in tests where I
# want the full logic to run
actual_result = some_complex_logic()
return flask.jsonify(actual_result)
But the downside of this approach is that having something that is essentially a massive exploit sitting at the core of the entrypoint, which will undergo lots of changes during the code's lifetime, feels somewhat risky to me.
An alternative approach that I've been considering was to have conditional wrappers that add the test-functionality. It would avoid having the test code within the actual code, and might print big red warning messages on startup during ENV != production to make it obvious that the server is insecure. Downside here would be that the stack traces would look slightly different.
To get all the constraints together in a short list:
- I don't want to fully replace the functions, so mocks won't do
- I don't want to add special test-only parameters to the request body
- I don't want to deploy different builds on my test and production servers, only the configuration (i.e.
ENVwill be eitherproductionor something different) should be different - Canned requests that produce the desired results are not good enough - the logic of
some_complex_logicchanges, the API changes, and on top of all it's a little random - I'm not talking about setting up a test client, I want an actual server to run and be tested on by humans
Optimally, there is just a different programming paradigm that I should follow, or maybe a middleware that I failed to google that handles this nicely and without risk.
edit:
I ended up writing and releasing a generalized variant of this problem, Flask-Shortcut. Thanks @vulpxn for suggesting the decorator form, and @davidism for linking to additional info (and maintainig Flask in the first place ).