'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