AngularJS with python flask test fails - python

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.

Related

Can't serve swagger on remotely hosted server with different url

I'm trying to serve some simple service using flask and flask_restx (a forked project of flask-restplus, that would be eventually served on AWS.
When it is served, I want to generate swagger page for others to test it easily.
from flask import Flask
from flask_restx import Api
from my_service import service_namespace
app = Flask(__name__)
api = Api(app, version='1.0')
api.add_namespace(service_namespace)
if __name__ == '__main__':
app.run(debug=True)
When I test it locally (e.g. localhost:5000), it works just fine. Problem is, when it is hosted on AWS, because it has a specific domain (gets redirected?) (e.g. my-company.com/chris-service to a container), the document page is unable to find its required files like css and so:
What I've looked and tried
Python (Flask + Swagger) Flasgger throwing 404 error
flask python creating swagger document error
404 error in Flask
Also tried adding Blueprint (albeit without knowing exactly what it does):
app = Flask(__name__)
blueprint = Blueprint("api", __name__,
root_path="/chris-service",
# url_prefix="/chris-service", # doesn't work
)
api = Api(blueprint)
app.register_blueprint(blueprint)
...
And still no luck.
Update
So here's more information as per the comments (pseudo, but technically identical)
Access point for the swagger is my-company.com/chris (with or without http:// or https:// doesn't make difference)
When connecting to the above address, the request URL for the assets are my-company.com/swaggerui/swagger-ui.css
You can access the asset in my-company.com/chris/swaggerui/swagger-ui.css
So I my resolution (which didn't work) was to somehow change the root_path (not even sure if it's the correct wording), as shown in What I've looked and tried.
I've spent about a week to solve this but can't find a way.
Any help will be greatful :) Thanks
Swagger parameters defined at apidoc.py file. Default apidoc object also created in this file. So if you want to customize it you have change it before app and api initialization.
In your case url_prefix should be changed (I recommend to use environment variables to be able set url_prefix flexibly):
$ export URL_PREFIX='/chris'
from os import environ
from flask import Flask
from flask_restx import Api, apidoc
if (url_prefix := environ.get('URL_PREFIX', None)) is not None:
apidoc.apidoc.url_prefix = url_prefix
app = Flask(__name__)
api = Api(app)
...
if __name__ == '__main__':
app.run()
Always very frustrating when stuff is working locally but not when deployed to AWS. Reading this github issue, these 404 errors on swagger assets are probably caused by:
Missing javascript swagger packages
Probably not the case, since flask-restx does this for you. And running it locally should also not work in this case.
Missing gunicorn settings
Make sure that you are also setting gunicorn up correctly as well with
--forwarded-allow-ips if deploying with it (you should be). If you are in a kubernetes cluster you can set this to *
https://docs.gunicorn.org/en/stable/settings.html#forwarded-allow-ips
According to this post, you also have to explicitly set
settings.FLASK_SERVER_NAME to something like http://ec2-10-221-200-56.us-west-2.compute.amazonaws.com:5000
If that does not work, try to deploy a flask-restx example, that should definetely work. This rules out any errors on your end.

Publish a script online

I have a Python script written up and the output of this script is a list.
Right now I need to get it online and make it accessible to others. I looked at Django , but then I realized that it may be kind of hard to create the UI. Is there any simple way to create a UI in Django and map it to an existing Python script.
Right now I using nltk, numpy, sqlite3 and things like that. Or is there a simpler way by which I can proceed?
In your case, Django is redundant.
You can use something smaller, Flask or maybe Aiohttp.
For example, all you need in aiohttp:
basic hmtl template
handler for one url (here you will call your script)
aiohttp webserver
The main idea:
Your server catch some url (for example /),
start your script, receives result,
respond with your html template (also render script result in it).
You can try creating a flask App.
Just do a pip install Flask and try the code below
from flask import Flask
import flask
import json
from flask import Response
app = Flask(__name__)
#app.route('/test',methods=['GET'])
def test():
'''
GET: Receives the request in /test route and returns a response containing {"response": [1,2,3]}
'''
my_list = [1,2,3]
resp = Response(response=json.dumps({"response": my_list}), status=200, mimetype='application/json')
return resp
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=8082)
Then to test your app from your browser accessing
localhost:8082/test
or also through some app like postman
I would suggest looking into something like React for creating the UI. This way your UI would only make calls to your Flask server.

Flask and Swagger UI does not work?

I am trying to create a RESTful app using Flask and swagger. But when I run the endpoint I do not see the methods documented in the browser like described here for example http://michal.karzynski.pl/blog/2016/06/19/building-beautiful-restful-apis-using-flask-swagger-ui-flask-restplus/
Instead just the 404 not found error. Here is my code:
def init_deserializer_restful_api():
# Get port number for the web app.
PORT = 8000
# Initiate the Flask app
app = Flask(__name__)
Swagger(app)
CORS(app)
# Handler for deserializer
#app.route("/deserialize", methods=['POST','GET'])
def handle_deserialization_request():
# Method description
# Method content
App is run like this:
app.run(port=PORT, host="0.0.0.0")
I run http://localhost:8000/deserializer I get The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
Questions:
1. How do I feed flask the request.json it requires?
2. How do I get swagger to work?
try localhost:8000/apidocs/index.html
Explanation
This is the default endpoint of Swagger. What you were trying to do is accessing one endpoint of your API and expecting it to render the Swagger UI. Swagger UI is an ADDITIONAL endpoint to your API which lists and lets you try all other endpoints. Hope that helps!

How to pass URLs as parameters in a GET request within python flask (restplus)?

I am creating a REST API using python flask. The API is ready and works on port number 8000 of my localhost. Now I intend to give this REST API a user friendly interface for which I decided to go with python - restplus. I thought of calling this service (running on 8000) internally from swagger application running on 5000
I was able to create the basic structure of the API (Swagger). The code for which looks like this:
import flask
from flask import Flask, request
from flask_restplus import Resource, Api
app = Flask(__name__)
api = Api(app)
#api.route('/HybridComparator/<string:url2>/<string:url1>')
class HybridComparator(Resource):
def get(self, url1, url2):
print(url1)
print(url2)
return url1 + ' ' + url2
if __name__ == '__main__':
app.run(debug=True)
The application as a whole runs seamlessly (with random strings as parameters) on port 5000. But when the URLs I pass are actual links, the application returns a response of 404 - Not found. Further to my investigation I realized the culprit being '/' embedded within the links I try to provide. Is there a way to handle URLs in particular?
Should I encode them before sending a request. (This will make my parameters look ugly). Is there something I am missing?
This is an entirely old question and I am sure you solved your problem by now.
But for new searchers, this may come in handy;
replace <string:url2>/<string:url1> with <path:url2>/<path:url1>
it seems that :
#api.route('/HybridComparator/<path:url2>/<path:url1>')
should fix it ,it fixes the 404 but i am getting only "http:/" part of the param

Extremely long wait time when loading REST resource from angularjs

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!

Categories