2

I'm trying to extend an existing Python 3 application to include a REST API. I've been searching for several days trying to figure out how to make the REST API a subcomponent of the existing application, but the guides I'm finding for things like Flask, Eve, etc. don't show how to run a production API unless the API application itself is run directly.

I have successfully added a Flask REST API to my application and it responds as expected. However, it is running in a way that is unsupported and allegedly unsafe, at least according to the developers. A warning message is produced when I run my application suggesting I should be using a WSGI server instead:

 * Serving Flask app "api" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off

Admittedly, I am new to this, so I'm not sure what that means or if/how it will work in my situation. Effectively, I'm trying to do this:

import api as API

class Stuff(object):

  def setup(self):
    ...
    self.apiThread = API(...)

  def run(self):
    ...
    self.apiThread.start()  

The application is large, complex, mature, and stable, so I can't and/or don't know how to make it work as subcomponent of an API application like this:

from werkzeug.wrappers import Request, Response

@Request.application
def application(request):
    return Response('Hello, World!')

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, application)

I've seen guides like this that have helped me understand the guts of a webserver to some degree, but I can't find a production solution that makes sense to me yet. Am I supposed to implement a class like what is shown on page 2 and then instantiate it in a thread like I showed in my example Stuff class? Would that work correctly or am I still missing something?

Any guidance would be greatly appreciated.

Edit: The gunicorn suggestions seem to be common and correct for many use cases - possibly including mine - but I don't understand why yet. The information on the gunicorn page says this on the first line:

If you want to deploy your Flask application to a WSGI server...

I'm already stuck because I have not built a flask application. I am running a flask server in a thread as a very minor part of a much larger application. I don't understand how to flip this around, so to speak.

Anthony
  • 1,760
  • 1
  • 23
  • 43
  • 1
    If this is used _only_ internally, you can probably ignore that warning – roganjosh Mar 10 '19 at 15:47
  • @roganjosh It's an internal app, so what you're saying is logical and that's part of the reason I've had this issue on the back-burner for a while. However, I'm trying to do it 'correctly' now that I have some time. I would really like to understand if what I'm asking is even possible because it seems like a situation that is not detailed online as far as I can tell. Either no one does this or the solutions are all internal/custom. – Anthony Mar 10 '19 at 15:53
  • 1
    Oh, of course it's possible. Launch with `gunicorn`. http://flask.pocoo.org/docs/1.0/deploying/ – roganjosh Mar 10 '19 at 15:55
  • I've been told to do that in the past, so it seems like it's common, but I don't understand the application flow at all. Right now, I'm running a python app as a service when the machine/VM boots. It's an extensive application that interacts with hardware (sensors, motors, etc.), a database, and a number of other things. It seems like launching something with `gunicorn` means the application is primarily a webserver, but that isn't the case here. The webserver/REST server is a small component of a greater application. – Anthony Mar 10 '19 at 15:59
  • 1
    So what you're saying is that you're serving your application on the development server and it's only the API that's now concerning you? – roganjosh Mar 10 '19 at 16:05
  • Yes, I think that's what I'm saying. The application is for industrial control and it needs to be configurable on the fly, so a REST server would make a lot of sense in my opinion. The REST server, if that's the right word here, would communicate with the 'parent' application to modify settings, configurations, hardware, etc. I would like it to run with a production-level API framework, but it doesn't make sense to me to run the application as a webserver from the top level. It needs to be embedded in the application somehow. – Anthony Mar 10 '19 at 16:07
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/189771/discussion-between-anthony-and-roganjosh). – Anthony Mar 10 '19 at 16:09
  • 1
    Well, this is exactly what I'm building myself. The server is responsible for transferring content to the front end. I develop of the development server but the main application uses gunicorn. The warning is about how the development server might choke on concurrent requests. Either ignore it or move to gunicorn. Nothing (in terms of your code) changes if you serve your app that way – roganjosh Mar 10 '19 at 16:11

2 Answers2

2

nginx together with gunicorn and flask are a common combination in the Python world. Here is a short explanation as to why you don't want to go with the basic development server (and here is a short tutorial on setting up just that). You're a bit vague about your goals so hard to recommend something very concrete for your case but this is safe, battle-tested and widely supported approach.

You could start the API server and just have the various flask routes import and call parts of your application as necessary (e.g. the /reload route could call whatever methods make sense for reloading the configuration of your app).

An even better approach would be to run the API server and your application separately and establish a communication channel between them using some traditional IPC , or, depending on your needs, something like zeromq (examples here).

Nobilis
  • 7,310
  • 1
  • 33
  • 67
1

Your options depend on what you mean by "Making it a subcomponent of the existing application".

Currently you have a completely separate app, which you could run using common App Servers like Gunicorn (this article might help and this as well [mentioned by @roganjosh]).

If you want to extend your mature application to include this, the solution depends mostly on the existing app and the framework you're using - I'll try to help if you add more details.

Maurice
  • 11,482
  • 2
  • 25
  • 45
  • 1
    Sorry, I tried to add as much detail as I could, so I'm not sure what type of information would be most helpful to you. From another comment I made a minute ago: "Right now, I'm running a python app as a service when the machine/VM boots. It's an extensive application that interacts with hardware (sensors, motors, etc.), a database, and a number of other things. It seems like launching something with gunicorn means the application is primarily a webserver, but that isn't the case here. The webserver/REST server is a small component of a greater application." – Anthony Mar 10 '19 at 16:01
  • 1
    Is the other application written in python as well? – Maurice Mar 10 '19 at 16:03
  • Yes, it is. The `Stuff` class is a very simple, but very accurate version of the main application. The API is currently instantiated in a thread in a `setup` function and then it is started later. There are many other threads running everything from database updates to hardware/IO control. – Anthony Mar 10 '19 at 16:05
  • 1
    Something is wonky here, beyond your question – roganjosh Mar 10 '19 at 16:06
  • I don't understand what you mean. Consider this as a fairly typical, but extensive, industrial control application. Being able to interact with it remotely is a reasonable thing to want to do and REST, being ubiquitous, seems like a reasonable choice for an API solution. – Anthony Mar 10 '19 at 16:08
  • 1
    @Anthony it's totally reasonable. I'm not saying it isn't. Your objections (If we call them that) don't make sense. Just launch with gunicorn :) – roganjosh Mar 10 '19 at 16:13
  • 1
    You can start a flask app after booting the system as [seen here](https://stackoverflow.com/questions/33586346/start-python-flask-webserver-automatically-after-booting-the-system-and-keep-it). You can also [execute a code before the flask app have started](https://stackoverflow.com/questions/50249681/how-to-run-the-code-before-the-app-run-in-flask). – victortv Mar 10 '19 at 16:40