how to fix Flask RESTful api server endpoint failing problem? - python

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)

Related

API ok from localhost but failed with Ajax - ERR_CONNECTION_REFUSED

I have a very minimal API (let's call it api.py) using Flask :
from flask import Flask, request
from flask_restx import Resource, Api
from flask_cors import CORS
app = Flask(__name__)
cors = CORS(app)
api = Api(app)
#api.route('/hello')
class HelloWorld(Resource):
def get(self):
return {"hello" : "world"}
if __name__ == '__main__':
app.run(port=5000)
}`
I then run : python3 api.py, no error
On another command line, I then query the API
curl http://localhost:5000/hello
which give me the right answer : {"hello": "world"}
On its side, the Flask App says : 127.0.0.1 - - [21/May/2020 22:55:38] "GET /hello HTTP/1.1" 200 -
Which seems ok to me
I then build a JS / Ajax Query to query the API from a WebPage :
$.ajax({
url: "http://localhost:5000/hello"
, type: "GET"
, contentType: "application/json"
, dataType: "json"
, success: function(data) {
console.log(data)
}
})
When I access the Web Page that fires the Ajax call, I get the following error message :
GET http://localhost:5000/hello net::ERR_CONNECTION_REFUSED
I understand that is a CORS issue. The problem is that I did test ALL the tricks from SO and other help forums with no success...
I did try :
from flask_cors import CORS
app.run(host="0.0.0.0", debug=True)
app.run(host="0.0.0.0", debug=False)
#cross-origin
...
Nothing works, I still have this ERR_CONNECTION_REFUSED
Thanks for any help on that subject, as I am loosing my head with that problem...
Your ajax call shouldn't be pointing to localhost. Replace it with the URL of the EC2 instance.
No need to configure Nginx to listen on your app's port for this task. Or exposing this port outside on the remote host.
But yes, for remote server setup ajax call shouldn't be pointing to the localhost. You need to update it to the url you see in the browser. So either machine IP or a DNS.
While for local machine debugging you could try 127.0.0.1 instead of localhost.
The second part of making this work is to deal with CORS:
for remote server CORS should be enabled both in the app (as middleware) and in the preflight request (see how to allow CORS for OPTIONS requests);
for local machine I would recommend disabling CORS by running the browser in disabled security mode (like disable-web-security flag for Chrome etc.).

Falcon cors with Angular 2

I do not understand the setup below used to work but it suddenly broke.
I configured CORS on Falcon as follow (I run it via gunicorn):
cors = CORS(
allow_all_origins=True,
allow_all_headers=True,
allow_all_methods=True
)
api = application = falcon.API(
middleware=[
cors.middleware,
auth_middleware,
sqlalchemy_middleware
]
)
On AngularJS
return this.authHttp.get(CONFIG.apiUrl + '/user').map(
(res: Response) => res.json());
Using http.get with manually setting the token does not work.
I have access to my token in localStorage.getItem('token').
I have got the following errors:
zone.js:2019 OPTIONS http://0.0.0.0:8000/user 401 (Unauthorized)
XMLHttpRequest cannot load http://0.0.0.0:8000/user. Response for preflight has invalid HTTP status code 401
I searched everywhere on the internet and I understand it is a server issue... However the server used to work with that configuration.
Let me know if you have any idea.
Cheers,
The solution was simple, I needed to disable the authentication from the FalconAuthMiddleware on 'OPTIONS' requests in my controller.
auth = {
'exempt_methods': ['OPTIONS']
}

Python app running on Google app engine. How to make calls to Google Maps API?

I've managed to write a simple Python app using webapp2 to make requests to Google maps. When I run a local server, the requests are valid and everything works. I uploaded my contents to google's app engine and deployed it. Because of the change in environment, when I make a request, the IP address isn't white listed in my app engine configurations. Every time I add an address, the address changes.
Long story short: python app running webapp2 makes calls to google maps locally but can't when deployed on app engine.
Is there a specific module/library I should be using? I've looked everywhere but most solutions are deprecated or ask to use google.appengine.api which doesn't seem like it has what I need.
EDIT
Here's the code. The API call is made in mapRequests.getMapRequests()
when you run a local server and visit
http://localhost:8080/map/nearby/?radius=5000&latitudeUser=40.905451&longitudeUser=-74.838134&query=italian
__init__.py
import webapp2
import json
import cgi
import config
from mapRequests import *
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.write('**************************')
class mapHandler(webapp2.RequestHandler):
def get(self,requestType,latitudeUser=None,longitudeUser=None,radius=None,query=None,referenceId=None):
finder = mapRequests()
self.response.headers['Content-Type'] = 'text/plain'
latitudeUser = cgi.escape(self.request.get('latitudeUser'))
longitudeUser = cgi.escape(self.request.get('longitudeUser'))
radius = cgi.escape(self.request.get('radius'))
query = cgi.escape(self.request.get('query'))
referenceId = cgi.escape(self.request.get('referenceId'))
options = {
'nearby' : finder.getMapRequest(latitudeUser,longitudeUser,radius,query),
'location' : finder.getRestaurantQuery(referenceId)
}
self.response.write(options[requestType])
self.response.write(finder.getMapRequest(latitudeUser,longitudeUser,radius,query))
app = webapp2.WSGIApplication([
('/', MainPage),
('/map/(nearby|location)/',mapHandler)
], debug=True)
mapRequests.py
import json
import config
import urllib
class mapRequests():
def __init__(self):
self.error = {'status': 'FAIL'}
return
# Get nearby locations within specified radius
def getMapRequest(self,latitudeUser,longitudeUser,radius,query):
....
val = {
'location': latitudeUser+','+longitudeUser,
'radius': radius,
'name': query,
'type': 'food',
'key': config.GOOGLE_PLACES_KEY
}
params = urllib.urlencode(val)
resp = urllib.urlopen("https://maps.googleapis.com/maps/api/place/nearbysearch/json?%s" % params)
return resp.read()
# Get additional details about a particular location
def getRestaurantQuery(self,referenceId):
if not referenceId:
self.error['referenceId'] = 'MISSING'
return(json.dumps(self.error))
return "Looking for a place\n"
This is what Google responds with when this is deployed and run on the app engine
{
"error_message" : "This IP, site or mobile application is not authorized to use this API key. Request received from IP address 107.178.195.162, with empty referer",
"html_attributions" : [],
"results" : [],
"status" : "REQUEST_DENIED"
}
When I say the IP changes, what I mean is when I add the IP seen here to the white list in my developer console, and then run the request again, it changes.
Although the only similarity is the 107.178.().() subnet so I'll tinker with that as one person mentioned here. I'll get back to you on that.
Any other suggestions what it might be?
Change your API key to allow the entire subnet of google app engine servers to make requests to the Google APIs
add 107.178.0.0/16 to your credential in this case

AngularJS with python flask test fails

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.

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