user6196039
user6196039

Reputation: 53

Can't make Restplus Flask API run using uWSGI

I'm working on a Flask API which works fine. I'm now trying to replace the Flask development server with uWSGI but everything breaks. I'm trying to solve this since 2 days, went through tutorials and searched here but couldn't find a solution to the problem. This is the code: app.py

import logging.config

import settings
import utils
from flask import Flask, Blueprint
from flask_restplus import Resource, Api
from flask_cors import CORS
from api.restplus import api
from api.gan.endpoints.client import ns as gan_client_namespace

# create Flask application
app = Flask(__name__)
CORS(app) # needed for cross-domain requests, allow everything by default

# load logging confoguration and create log object
logging.config.fileConfig('logging.conf')
log = logging.getLogger(__name__)

# 
@app.route("/")
def hello():
    return "Hello World!"

def __get_flask_server_params__():
    '''
    Returns connection parameters of the Flask application

    :return: Tripple of server name, server port and debug settings
    '''
    server_name = utils.get_env_var_setting('FLASK_SERVER_NAME', settings.DEFAULT_FLASK_SERVER_NAME)
    server_port = utils.get_env_var_setting('FLASK_SERVER_PORT', settings.DEFAULT_FLASK_SERVER_PORT)

    flask_debug = utils.get_env_var_setting('FLASK_DEBUG', settings.DEFAULT_FLASK_DEBUG)
    flask_debug = True if flask_debug == '1' else False

    return server_name, server_port, flask_debug

def configure_app(flask_app, server_name, server_port):
    '''
    Configure Flask application

    :param flask_app: instance of Flask() class
    '''
    flask_app.config['SERVER_NAME'] = server_name + ':' + server_port
    flask_app.config['SWAGGER_UI_DOC_EXPANSION'] = settings.RESTPLUS_SWAGGER_UI_DOC_EXPANSION
    flask_app.config['RESTPLUS_VALIDATE'] = settings.RESTPLUS_VALIDATE
    flask_app.config['RESTPLUS_MASK_SWAGGER'] = settings.RESTPLUS_MASK_SWAGGER
    flask_app.config['ERROR_404_HELP'] = settings.RESTPLUS_ERROR_404_HELP

def initialize_app(flask_app, server_name, server_port):
    '''
    Initialize Flask application with Flask-RestPlus

    :param flask_app: instance of Flask() class
    '''
    blueprint = Blueprint('tf_api', __name__, url_prefix='/tf_api')

    configure_app(flask_app, server_name, server_port)
    api.init_app(blueprint)
    api.add_namespace(gan_client_namespace)

    flask_app.register_blueprint(blueprint)

    #from werkzeug.contrib.fixers import ProxyFix
    #flask_app.wsgi_app = ProxyFix(flask_app.wsgi_app)

def main():
    server_name, server_port, flask_debug = __get_flask_server_params__()
    initialize_app(app, server_name, server_port)
    log.info(
        '>>>>> Starting TF Serving client at http://{}/ >>>>>'.format(app.config['SERVER_NAME'])
        )
    app.run(debug=flask_debug, host=server_name)

if __name__ == '__main__':
    main()

When I run this with python app.py it works fine.

Command Line Message

0.0.0.0:5001

0.0.0.0:5001/tf_api

Now I'm just trying to get the same results using uWSGI:

uwsgi --http :8000 --wsgi-file app.py --callable app

The command line message looks fine:

Command Line Message

Accessing 0.0.0.0:8000 also works

0.0.0.0:8000

However, when I try to access the API it fails: 0.0.0.0:8000/tf_api

I've tried everything that came to my mind but didn't manage to solve this. Some of the things I did were:

  1. Include the following code:

    from werkzeug.contrib.fixers import ProxyFix flask_app.wsgi_app = ProxyFix(flask_app.wsgi_app)

  2. Remove app.run() (Flask Gunicorn app can't get __name__ to equal '__main__')

  3. Move the function_calls outside the main function as otherwise they are only called when running app.py directly, similar to (Flask application with Blueprints+uWSGI+nginx returning 404's (no routing?))

I really have no idea what else could be the issue. I found a similar problem but it's not applicable to my situation because it's related to NGINX which I'm not using yet (How to deploy a flask-restplus app with nginx + uwgsi). Any ideas what else I could try? Maybe I'm missing something obvious, didn't sleep much because of this.

Upvotes: 2

Views: 1188

Answers (2)

Jerem_Lab
Jerem_Lab

Reputation: 36

Everything inside initialize_app is invisible by wsgi server, this will work

import logging.config

import settings
import utils
from flask import Flask, Blueprint
from flask_restplus import Resource, Api
from flask_cors import CORS
from api.restplus import api
from api.gan.endpoints.client import ns as gan_client_namespace

# create Flask application
app = Flask(__name__)
CORS(app) # needed for cross-domain requests, allow everything by default

# load logging confoguration and create log object
logging.config.fileConfig('logging.conf')
log = logging.getLogger(__name__)

# 
@app.route("/")
def hello():
    return "Hello World!"

server_name = utils.get_env_var_setting('FLASK_SERVER_NAME', settings.DEFAULT_FLASK_SERVER_NAME)
server_port = utils.get_env_var_setting('FLASK_SERVER_PORT', settings.DEFAULT_FLASK_SERVER_PORT)

flask_debug = utils.get_env_var_setting('FLASK_DEBUG', settings.DEFAULT_FLASK_DEBUG)
flask_debug = True if flask_debug == '1' else False


app.config['SERVER_NAME'] = server_name + ':' + server_port
app.config['SWAGGER_UI_DOC_EXPANSION'] = settings.RESTPLUS_SWAGGER_UI_DOC_EXPANSION
app.config['RESTPLUS_VALIDATE'] = settings.RESTPLUS_VALIDATE
app.config['RESTPLUS_MASK_SWAGGER'] = settings.RESTPLUS_MASK_SWAGGER
app.config['ERROR_404_HELP'] = settings.RESTPLUS_ERROR_404_HELP

blueprint = Blueprint('tf_api', __name__, url_prefix='/tf_api')

api.init_app(blueprint)
api.add_namespace(gan_client_namespace)

flask_app.register_blueprint(blueprint)


def main():
    log.info(
        '>>>>> Starting TF Serving client at http://{}/ >>>>>'.format(app.config['SERVER_NAME'])
        )
    app.run(debug=flask_debug, host=server_name)

if __name__ == '__main__':
    main()

Upvotes: 2

Alex R
Alex R

Reputation: 666

You are calling your app.register_blueprint in a function that will never be seen by the wsgi server.

I'm guessing you have followed some kind of guide that makes these nice functionsfor you to configure/initialise etc the app. But it is purely made for the development server it would seem.

You have to call Blueprint and init_app outside the functions, or create a new wsgi.py file that imports app and then runs the Blueprint and api.init_app commands.

Upvotes: 0

Related Questions