'Object Oriented Python with Flask Server?
I'm using Flask to expose some data-crunching code as a web service. I'd like to have some class variables that my Flask functions can access.
Let me walk you through where I'm stuck:
from flask import Flask
app = Flask(__name__)
class MyServer:
def __init__(self):
globalData = json.load(filename)
@app.route('/getSomeData')
def getSomeData():
return random.choice(globalData) #select some random data to return
if __name__ == "__main__":
app.run(host='0.0.0.0')
When I run getSomeData() outside of Flask, it works fine. But, when I run this with Flask, I get 500 internal server error. There's no magic here, and Flask has no idea that it's supposed to initialize a MyServer object. How can I feed an instance of MyServer to the app.run() command?
I could admit defeat and put globalData into a database instead. But, is there an other way?
Solution 1:[1]
I know this is a late reply, but I came across this question while facing a similar issue. I found flask-classful really good. You inherit your class from FlaskView and register the Flask app with your MyServer class
http://flask-classful.teracy.org/#
In this case, with flask-classful, your code would look like this:
from flask import Flask
from flask_classful import FlaskView, route
app = Flask(__name__)
class MyServer(FlaskView):
def __init__(self):
globalData = json.load(filename)
@route('/getSomeData')
def getSomeData():
return random.choice(globalData) #select some random data to return
MyServer.register(app, base_route="/")
if __name__ == "__main__":
app.run(host='0.0.0.0')
Solution 2:[2]
The least-coupled solution is to apply the routes at runtime (instead of at load time):
def init_app(flask_app, database_interface, filesystem_interface):
server = MyServer(database_interface, filesystem_interface)
flask_app.route('get_data', methods=['GET'])(server.get_data)
This is very testable--just invoke init_app() in your test code with the mocked/faked dependencies (database_interface and filesystem_interface) and a flask app that has been configured for testing (app.config["TESTING"]=True or something like that) and you're all-set to write tests that cover your entire application (including the flask routing).
The only downside is this isn't very "Flasky" (or so I've been told); the Flask idiom is to use @app.route(), which is applied at load time and is necessarily tightly coupled because dependencies are hard-coded into the implementation instead of injected into some constructor or factory method (and thus complicated to test).
Solution 3:[3]
a bit late but heres a quick implementation that i use to register routes at init time
from flask import Flask,request,render_template
from functools import partial
registered_routes = {}
def register_route(route=None):
#simple decorator for class based views
def inner(fn):
registered_routes[route] = fn
return fn
return inner
class MyServer(Flask):
def __init__(self,*args,**kwargs):
if not args:
kwargs.setdefault('import_name',__name__)
Flask.__init__(self,*args ,**kwargs)
# register the routes from the decorator
for route,fn in registered_routes.items():
partial_fn = partial(fn,self)
partial_fn.__name__ = fn.__name__
self.route(route)(partial_fn)
@register_route("/")
def index(self):
return render_template("my_template.html")
if __name__ == "__main__":
MyServer(template_folder=os.path.dirname(__file__)).run(debug=True)
Solution 4:[4]
The following code is a simple solution for OOP with Flask:
from flask import Flask, request
class Server:
def __init__(self, name):
self.app = Flask(name)
@self.app.route('/')
def __index():
return self.index()
@self.app.route('/hello')
def __hello():
return self.hello()
@self.app.route('/user_agent')
def __user_agent():
return self.user_agent()
@self.app.route('/factorial/<n>', methods=['GET'])
def __factorial(n):
return self.factorial(n)
def index(self):
return 'Index Page'
def hello(self):
return 'Hello, World'
def user_agent(self):
return request.headers.get('User-Agent')
def factorial(self, n):
n = int(n)
fact = 1
for num in range(2, n + 1):
fact = fact * num
return str(fact)
def run(self, host, port):
self.app.run(host=host, port=port)
def main():
server = Server(__name__)
server.run(host='0.0.0.0', port=5000)
if __name__ == '__main__':
main()
To test the code, browse the following urls:
- http://localhost:5000/
- http://localhost:5000/hello
- http://localhost:5000/user_agent
- http://localhost:5000/factorial/10
Solution 5:[5]
if you wish to approach MyServer class as a resource
I believe that flask_restful can help you:
from flask import Flask
from flask_restful import Resource, Api
import json
import numpy as np
app = Flask(__name__)
api = Api(app)
class MyServer(Resource):
def __init__(self):
self.globalData = json.load(filename)
def get(self):
return np.random.choice(self.globalData)
api.add_resource(MyServer, '/')
if __name__ == '__main__':
app.run()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | tristndev |
| Solution 2 | |
| Solution 3 | Joran Beasley |
| Solution 4 | Amir Saniyan |
| Solution 5 | talp |
