I'm building a front-end in angular that is accessing a flask/python RESTful API. I'm using AngularJS v1.2.16.
For some reason, it takes an insane amount of time before the REST resource is loaded, with most of the time just waiting. It's my understanding that 'waiting' is measuring the time to first byte - all my services run locally (the frontend, API and database).
Given that the services all run locally, I am at a loss how to debug this. Does anybody have any tips on where to look? I checked all my methods and they run decently fast (under 100ms per REST call). When I use postman, the API returns near-instantly.
Any ideas how to fix the wait, it only seems to be the case when loading the RESTful resource via angular. The angular $http get request is fairly straight forward:
myAppControllers.controller('ManageCtrl', ['$scope', '$http',
function($scope, $http) {
$http({
url: 'http://127.0.0.1:5000/v1/domains/',
method: "GET",
headers: { 'Content-Type': 'application/json' },
}).
success(function(data, status, headers, config) {
console.log('login successful');
console.log(status);
console.log(data);
}).
error(function(data, status, headers, config) {
console.log('login failed');
});
}]);
EDIT:
the issue only appears in Google Chrome, regular mode.
the GET requests are fast when using incognito mode.
We had the same problem and after some research the problem is related with the way Chrome uses connections and the default configuration of flask as mono threaded.
Added threaded=true when flask app is started solved the problem:
app.run(threaded=True)
I've run into the same issue (Angular frontend running in Chrome and Flask backend). After trying both Angular 1.2.x and 1.3.x, and a billion other permutations, the only "solution" I've found is to run the Flask backend with the Tornado web server (http://www.tornadoweb.org/en/stable/). Other WSGI containers may work, but this is the one I tested.
In your Flask application, paste the following:
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
if __name__ == '__main__':
http_server = HTTPServer(WSGIContainer(app))
http_server.listen(5000)
IOLoop.instance().start()
You can start your web server by typing:
python myserver.py
I am facing now very similar issue. My current solution (acceptable for my chef at this moment :) ), which unfortunately not remove all problems, is to set header:{ 'Content-Type': 'application/json' } to { 'Content-Type': 'text/plain' }. Now only first GET request is crazy slow, any next takes less than 500ms. I am using Restangular on the frontend and wsgiref.simple_server on the backend.
I wanted to tie this in as well. But
app.run(threaded=True)
worked for me!
Related
UPDATE 3:
From Miguel Grinberg: "Like most Google APIs, Dialogflow is incompatible with eventlet and gevent, and Google hasn't shown interest in adding support."
If anyone knows how I can get DialogFlow to work with flask-socketio, please let me know. Or more generally, what's a good way to build a python websocket chat app that also includes a bot.
UPDATE 2:
I found the culprit. At the top of my code, after import eventlet, I had this line:
eventlet.monkey_patch()
This line blocks access to dialogFlow. When I comment it out, everything works fine. Unfortunately, I think this patch needs to be implemented for socketio to work.
More here: https://github.com/miguelgrinberg/Flask-SocketIO/issues/696
UPDATE 1:
I created another app following this tutorial: https://medium.com/zenofai/creating-chatbot-using-python-flask-d6947d8ef805
This app is much simpler, just focusing on dialogFlow. I used the same google project and dialogflow credentials as my original app. This new app works fine with dialogFlow. Why wouldn't dialogFlow work in my original app with same google project, credentials, and identical code blocks making the request to dialogFlow? Is there some kind of conflict with other parts of my flask socketio chat app?
ORIGINAL POST:
I'm trying to use Google's Dialogflow fulfillment in my flask socket-io chat app.
It hangs for a few minutes and then I get this error message:
Deadline of 220.0s exceeded while calling functools.partial(<function _wrap_unary_errors.<locals>.error_remapped_callable at 0x00000189C3C77C80>, session: "projects/webhook-agent-tmpe/agent/sessions/riverscuomo"
query_input {
text {
text: "howdy"
language_code: "en"
}
}
, metadata=[('x-goog-request-params', 'session=projects/webhook-agent-tmpe/agent/sessions/riverscuomo'), ('x-goog-api-client', 'gl-python/3.6.3 grpc/1.32.0 gax/1.21.0 gapic/1.1.0')]), last exception: 503 Deadline Exceeded
I ended up using Chatterbot instead: https://chatterbot.readthedocs.io/en/stable/
It works with a Heroku-deployed flask-socketio chat app.
I am new to api development using openapi sepc, so I followed this blog where I just used server artifact to understand the code. I used /openapi/photo_album/codegen_server for my simple work. To do so, I downloaded the file and tried to run server on default server end point. I installed all required dependencies and hit python -m openapi_server, but browser endpoint always keep bugging me with following error message:
{ "detail": "The requested URL was not found on the server. If you
entered the URL manually please check your spelling and try again.",
"status": 404, "title": "Not Found", "type": "about:blank" }
my attempt
here is the sourcecode that I tried:
I also tried the following:
import connexion
from openapi_server import encoder
def main():
app = connexion.App(__name__, specification_dir='./openapi/')
app.app.json_encoder = encoder.JSONEncoder
app.add_api('openapi.yaml', arguments={'title': 'Sample OpenAPI Specification'})
app.run(host='127.0.0.1',port=5000, debug=True)
if __name__ == '__main__':
main()
I tried to close firewall and tried to access server endpoint, still is not working. I am using windows-x64 for my system, this is first time I am trying to work with api development. I don't know what's going on and how to fix my problem. even I tried route print -4 and ping 127.0.0.1 on cmd and tried to use local ipv4 address but still not working. My intension is to make request to default server endpoint and do basic api testing. Can anyone provide possible solution how to fix this bug? any quick solution? thanks
update:
I tried any flask rest api sample project on my windows machine, none of them works, server endpoint is always failing. Is that because of my local machine setting? this error is killing me, how to fix this? any quick solution? thanks
I figured out this problem by updating connexion==2.6.0 in requirements. Also using different value for host, port would run the server on default endpoint. This source code has some issue since code is generated by openapi code generator, there is no guarantee that sample api server run. my recent observation for api development, is to use flask-restplus which come with nice UI api view on server endpoint.
This is test api by using flask-restplus, hope whoever new to flask-restplus API development find it useful.
from flask import Flask
from flask_restplus import Api, fields, Resource, marshal
app = Flask(__name__)
api = Api()
api.init_app(app)
metadata_model = api.model("metadata", {
'file': fields.String()
})
user_model = api.model('UserModel', {
"user_id": fields.Integer(required=True, description=''),
"user_name": fields.String(required=True, description=''),
"user_role": fields.String(required=False, description='')
})
response_model = api.model("Result", {
'metadata': fields.List(fields.Nested(metadata_model)),
'result': fields.Raw()
})
#api.route("/test")
class ApiView(Resource):
#api.marshal_with(response_model)
def get(self):
data = {'metadata': {},
'result': self.get_user()}
return data
def get_user(self):
# Access database and get data
user_data = [{'user_id': 1, 'user_name': 'John', 'user_role': 'editor'},
{'user_id': 2, 'user_name': 'Sue', 'user_role': 'curator'}]
# The kwarg envelope does the trick
return marshal(user_data, user_model, envelope='data')
app.run(host='127.0.0.1', port='8080', debug=True)
i'm learning to use python flask to complement angularJS. This is what i have on flask:
#!flask/bin/python
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/hola', methods=['GET'])
def get_tasks():
x="pepepepep"
return jsonify({'msj': x})
if __name__ == '__main__':
app.run(debug=True)
when i open in my browser:
http://127.0.0.1:5000/hola
i do indeed see the json object with that random message.
Now, when i go to angularJS, this is what i have on the controller:
function ControladorPrueba($scope,$http) {
$scope.mensaje="i";
$scope.ObtenerMsj= function(){
$http.get('http://localhost:5000/hola')
.success(function(data){
$scope.mensaje=data.msj;
})
.error(function(data,status){
$scope.mensaje = status;
});
};
}
The problem is that when this function is executed, the get always go on .error(...), any ideas of why this happens even when the service in flask works well when opened on the browser? am i missing something?
Any help appreciated. Thanks!
I suspect that this may be due to the Same-origin policy. If you're running your Flask app on localhost, and if you're serving your Angularjs files separately (for example, using the file:/// protocol), then the browser will actually forbid your Angular code from talking to the webservice for security reasons.
If this is the case, you have two solutions. You can either start serving your HTML/CSS/Javascript files from your Flask app, or by using something like Flask-Cors to explicitly set your server to allow external requests.
I am using a web service that will send a url callback when a particular external event happens (that service is monitoring it 24-7)
I need to have a python script running (locally on my own computer) and waiting (possibly just looping) to receive that callback and then do something with the data.
How do I do this? Do I need to have a webserver running? Where do I look for the data? I am pretty experienced with python, but not much in the use of HTTP and other web related things.
I have looked at other stackoverflow posts but they all seem to presume some prior knowledge.... I need the basics!
Here is a simple server using Bottle Microframework .
from bottle import Bottle, run, route, request
app = Bottle()
#app.route('/listener')
def my_listener():
data = request.query.your_data
#do_something_with_data(data)
return data
run(app, host="0.0.0.0", port=8080)
You can send data to server requesting http://sever_ip:8080/listener?your_data=some_data
Look into setting up a Flask server that will run in the background and listen for the callback request
I want to proxy requests made to my Flask app to another web service running locally on the machine. I'd rather use Flask for this than our higher-level nginx instance so that we can reuse our existing authentication system built into our app. The more we can keep this "single sign on" the better.
Is there an existing module or other code to do this? Trying to bridge the Flask app through to something like httplib or urllib is proving to be a pain.
I spent a good deal of time working on this same thing and eventually found a solution using the requests library that seems to work well. It even handles setting multiple cookies in one response, which took a bit of investigation to figure out. Here's the flask view function:
from dotenv import load_dotenv # pip package python-dotenv
import os
#
from flask import request, Response
import requests # pip package requests
load_dotenv()
API_HOST = os.environ.get('API_HOST'); assert API_HOST, 'Envvar API_HOST is required'
#api.route('/', defaults={'path': ''}) # ref. https://medium.com/#zwork101/making-a-flask-proxy-server-online-in-10-lines-of-code-44b8721bca6
#api.route('/<path>')
def redirect_to_API_HOST(path): #NOTE var :path will be unused as all path we need will be read from :request ie from flask import request
res = requests.request( # ref. https://stackoverflow.com/a/36601467/248616
method = request.method,
url = request.url.replace(request.host_url, f'{API_HOST}/'),
headers = {k:v for k,v in request.headers if k.lower() == 'host'},
data = request.get_data(),
cookies = request.cookies,
allow_redirects = False,
)
#region exlcude some keys in :res response
excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection'] #NOTE we here exclude all "hop-by-hop headers" defined by RFC 2616 section 13.5.1 ref. https://www.rfc-editor.org/rfc/rfc2616#section-13.5.1
headers = [
(k,v) for k,v in res.raw.headers.items()
if k.lower() not in excluded_headers
]
#endregion exlcude some keys in :res response
response = Response(res.content, res.status_code, headers)
return response
Update April 2021: excluded_headers should probably include all "hop-by-hop headers" defined by RFC 2616 section 13.5.1.
I have an implementation of a proxy using httplib in a Werkzeug-based app (as in your case, I needed to use the webapp's authentication and authorization).
Although the Flask docs don't state how to access the HTTP headers, you can use request.headers (see Werkzeug documentation). If you don't need to modify the response, and the headers used by the proxied app are predictable, proxying is staightforward.
Note that if you don't need to modify the response, you should use the werkzeug.wsgi.wrap_file to wrap httplib's response stream. That allows passing of the open OS-level file descriptor to the HTTP server for optimal performance.
My original plan was for the public-facing URL to be something like http://www.example.com/admin/myapp proxying to http://myapp.internal.example.com/. Down that path leads madness.
Most webapps, particularly self-hosted ones, assume that they're going to be running at the root of a HTTP server and do things like reference other files by absolute path. To work around this, you have to rewrite URLs all over the place: Location headers and HTML, JavaScript, and CSS files.
I did write a Flask proxy blueprint which did this, and while it worked well enough for the one webapp I really wanted to proxy, it was not sustainable. It was a big mess of regular expressions.
In the end, I set up a new virtual host in nginx and used its own proxying. Since both were at the root of the host, URL rewriting was mostly unnecessary. (And what little was necessary, nginx's proxy module handled.) The webapp being proxied to does its own authentication which is good enough for now.