Accessing a url in a Flask view - python

I am trying to access an external url https://data.dublinked.ie/cgi-bin/rtpi/realtimebusinformation?stopid=184&format=json in a Flask view
I get the error,
Not Found
The requested URL was not found on the server. If you entered the URL
manually please check your spelling and try again.
Is that my local server that flask is looking for this url on. And if so why? I am running flask locally.
The view, services.py
from flask import Flask, Response
import json
import urllib2
app = Flask(__name__)
#app.route('/')
def test():
return 'Everything is running!'
#app.route('/stopid')
def stopid():
dublin_bus_url = "https://data.dublinked.ie/cgi-bin/rtpi/realtimebusinformation?stopid=184&format=json"
response = urllib2.urlopen(dublin_bus_url)
json_response = json.load(response)
routes = set()
for result in json_response["results"]:
routes.add(result["route"])
return json.dumps(list(routes))
if __name__ == '__main__':
app.run()
The index.html and script is,
<!DOCTYPE html>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<script>
d3.json("/stopid", function(error, routes) {
routes.forEach(function(route) {
console.log(route)
});
});
</script>
</body>
</html>
I am new to Flask but this must not be the way to deal with an external link in a view.
The code above is adopted from this excellent tutorial for the Donorschoose api.
https://youtu.be/bzl4hCH2CdY
https://github.com/VidyaSource/starting-with-data
Thanks,

If we assume that the HTML file is not being served by flask:
You need to enable Cross origin resource sharing. You can do this by creating a response and setting it's header Access-Control-Allow-Origin to *: that is everyone. Or you can set it to your own domain when deploying.
resp.headers['Access-Control-Allow-Origin'] = '*'
Also, you're calling d3.json("/stopid" ... you need to change this to:
d3.json("http://localhost:5000/stopid" ...
Complete code:
from flask import Flask, Response, jsonify
import json
import urllib2
app = Flask(__name__)
#app.route('/')
def test():
return 'Everything is running!'
#app.route('/stopid')
def stopid():
dublin_bus_url = "https://data.dublinked.ie/cgi-bin/rtpi/realtimebusinformation?stopid=184&format=json"
my_response = urllib2.urlopen(dublin_bus_url)
json_response = json.load(my_response)
routes = set()
for result in json_response["results"]:
routes.add(result["route"])
resp = jsonify(list(routes))
resp.headers['Access-Control-Allow-Origin'] = '*'
return resp
if __name__ == '__main__':
app.run()
If the HTML is being served by flask, there is no need to enable cross origin sharing.
#app.route('/d3')
def d3():
return render_template('d3.html')
Call the link to this url using:
d3.json("{{ url_for('stopid') }}", ...
But this isn't exactly reliable, because you don't want to use the api using javascript when you can do it in flask itself.

Related

How to prevent Flask (python) from emitting html?

It appears that Flask assumes that the server is returning html to the client (browser).
Here's a simple example;
import json
from flask import Flask
app = Flask(__name__)
#app.route("/")
def home():
msg = ['Hello, world!']
return json.dumps(msg) + '\n'
This code works as expected and returns the desired json;
$ curl -s http://localhost:5000/
["Hello, world!"]
But if I introduce an error;
import json
from flask import Flask
app = Flask(__name__)
#app.route("/")
def home():
msg = ['Hello, world!']
return json.dumps(XXmsg) + '\n'
Then Flask emits the error wrapped in several pages worth of html, starting like;
$ curl -s http://localhost:5000/
<!DOCTYPE html>
<html>
<head>
<title>NameError: name 'XXmsg' is not defined
// Werkzeug Debugger</title>
<link rel="stylesheet" href="?__debugger__=yes&cmd=resource&f=style.css">
<link rel="shortcut icon"
href="?__debugger__=yes&cmd=resource&f=console.png">
<script src="?__debugger__=yes&cmd=resource&f=debugger.js"></script>
<script>
var CONSOLE_MODE = false,
EVALEX = true,
EVALEX_TRUSTED = false,
SECRET = "Mq5TSy6QE4OuOHUfvk8b";
</script>
</head>
<body style="background-color: #fff">
<div class="debugger">
Emitting html makes sense if you're creating a page load app. But I'm creating an api that only returns json.
Is there anyway to prevent Flask from emitting html at all?
Thanks
Mike
Have a look at the section Returning API Errors as JSON of the Flask docs.
Basically, you have to replace the default error handler with a function that returns the error as json. A very basic example:
#app.errorhandler(HTTPException)
def handle_exception(exception):
response = exception.get_response()
response.content_type = "application/json"
response.data = json.dumps({"code": exception.code})
return response
The accepted response gives a good hint for handling HTTPException but it won't work for all exceptions unless you create a handler for the mother of all exceptions:Exception. And you might not want to do this for security reasons, if you have some custom defined exceptions with sensible data it'll get handled by this handler.
I suspect the true reason you have those lengthy html responses is because you started your flask app with the --debug option.

500: Internal Server Error Spotify python Auth Code flow trying to redirect to login and get token

I am using this documentation to get the user to login and return me code and state. However, when I run my app It gives me a 500 error.
This is my app.py
import flask
import SpotifyOAuth
app = flask.Flask(__name__)
#app.route('/')
def index():
flask.render_template("index.html")
#app.route('/login')
def accessSpotify():
SpotifyOAuth.RedirectTologin(redirect_uri='https://localhost:7001/authorized')
#app.route('/authorized')
def SP_redirect_uri():
return "spotify connected"
def main():
print("nothin")
if __name__ == '__main__':
app.run(use_reloader=True,port=7001)
and this is my SpotifyOAuth.py
import requests
def RedirectTologin(redirect_uri="https://localhost:7001/authorized"):
token_uri="https://accounts.spotify.com/authorize"
method="GET"
params={
"client_id" : '<id>',
"response_type" : 'code',
"redirect_uri" : redirect_uri,
"scope" : 'user-read-email'
}
client_secret='<secret>'
r = requests.get(token_uri,params=params)
print(r)
if __name__=='__main__':
RedirectTologin()
I know my RedirectTLogin() is working because when I print r it gives me response code 200. Not sure where I am going wrong in app.py
Here is my index.html for reference
<html>
<body>
<div>
<div id="login">
<h1>First, log in to spotify</h1>
Log in
</div>
<div id="loggedin">
</div>
</div>
</body>
</html>
Does anyone see any issue? I don't have much experience working with APIs
Flask routes need to return something: a rendered template, a redirect, plain text with a status code, etc.
To fix your issue you need to add returns to index() and accessSpotify() as follows:
#app.route('/')
def index():
return flask.render_template("index.html")
#app.route('/login')
def accessSpotify():
SpotifyOAuth.RedirectTologin(redirect_uri='https://localhost:7001/authorized')
return flask.redirect(url_for('SP_redirect_uri'))

I have created a REST api which basically displays some data.I need to get this data to display through angularjs using $http

from flask import Flask, jsonify, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class display(Resource):
def get(self):
return jsonify({"message":"hello world"})
def post(self):
data = request.get_json() # status code
return jsonify({'data': data}), 201
class square(Resource):
def get(self, num):
return jsonify({'square': num**2})
api.add_resource(display, '/display')
api.add_resource(square, '/square/<int:num>')
driver function
if __name__ == '__main__':
app.run(port = '5008')
This is the html file created using angularjs.This sends http request to the url given and receives data and displays it on th html page.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<p>Today's welcome message is:</p>
<h1>{{message}}</h1>
</div>
<p>The $http service requests a page on the server, and the response is set as the value of "myWelcome" variable.</p>
<script>
var app = angular.module('app', []);
app.controller("myCtrl", function($http) {
var app = this;
$http.get("http://127.0.0.1:5008/display")
.success(function(data) {
app.message = data;
})
});
</script>
</body>
</html>
I am getting this error while running the code:
Today's welcome message is:
{{message}}
The $http service requests a page on the server, and the response is set as the value of "myWelcome" variable.

Flask restful - Can't see output from json post

I'm using flask to create api server, which get post of json data.
I used following this tutorial to create the code:
from flask import Flask
from flask import request
app = Flask(__name__)
#app.route('/postjson', methods = ['POST'])
def postJsonHandler():
print (request.is_json)
content = request.get_json()
print (content)
return 'JSON posted'
app.run(host='0.0.0.0')
When I run:
curl -X POST http://127.0.0.1:5000/postjson -H "Content-type: application/json" -d '{ "data": { "url": "https://google.com" }}'
I just see "JSON posted", without any print. Why can't I see any data?
I also tried to use POSTMAN, but same result.
I also tried the json in the example of the guide:
{
"device":"TemperatureSensor",
"value":"20",
"timestamp":"25/01/2017 10:10:05"
}
also the same.
EDIT- as #TomMP answer, when I tried the following code:
from flask import Flask
from flask import request
app = Flask(__name__)
#app.route('/producer', methods = ['POST'])
def postJsonHandler():
print (request.is_json)
content = request.get_json()
print (content)
return request.get_json()
#return 'JSON posted'
app.run(host='0.0.0.0')
I get:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
And When I try the debug mode, I get:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>TypeError: 'dict' object is not callable
The view function did not return a valid response. The return type must be a string, tuple, Response instance, or WSGI callable, but it was a dict. // Werkzeug Debugger</title>
<link rel="stylesheet" href="?__debugger__=yes&cmd=resource&f=style.css"
type="text/css">
... (more lines of data)
that because you only return text 'JSON posted'
so return what you want to get
like json responseļ¼š
return jsonify({'status': 0, 'msg': 'success'})
detail
from flask import Flask, request, jsonify
app = Flask(__name__)
#app.route('/postjson', methods = ['POST'])
def postJsonHandler():
content = request.json
print(content)
return jsonify(content)
app.run(host='0.0.0.0')
call example:
requests.post('http://0.0.0.0:5000/postjson', json={'a':'b'}).json()
When you use print() it simply prints everything to console, so check it for you running app to see printed output. What you return ('JSON posted') from your view is what gets sent back to the client as a response.
When you use curl to access a route, it will only show you what that route returned - in this case, that's JSON posted. It won't show you the print statements that are in between. You could try and run flask in debug mode. That should print out to the console where you're running this app from.
Edit: To be clear, you still won't receive the data you send as an answer to your request, i.e. in Postman. For this, you will have to return the data at the end of your function using return request.get_json()

Python requsts.post returning 405 error: The method is not allowed for the requested URL

Howdie do,
I'm just running a simple flask API call.
The flask API will take a XML request in and then parse the XML and print it to the terminal screen.
However, everytime I do this, I'm receiving
The method is not allowed for the requested URL
The Flask script is:
__author__ = 'Jeremy'
from flask import Flask
from flask import request
import xmltodict
app = Flask(__name__)
#app.route('/', methods=['POST'])
def parsexml():
xmlrequest = xmltodict.parse(request.data)
print xmlrequest
if __name__ == '__main__':
app.run()
The script that sends the XML is:
__author__ = 'Jeremy'
import requests
xml = """
<dtc:GetShipmentUpdates>
<dtc:GetShipmentUpdatesRequest>
<dtc:SearchStartTime>2015-07-12T12:00:00</dtc:SearchStartTime>
<dtc:SearchEndTime>2015-07-12T12:30:00</dtc:SearchEndTime>
</dtc:GetShipmentUpdatesRequest>
</dtc:GetShipmentUpdates> """
headers = {'Content-Type': 'application/xml'}
r = requests.post('http://127.0.0.1:5000/', data=xml, headers=headers)
print r.content
Does anyone know why this is happening and if so, how can I send a POST request to my flask application running on 127.0.0.1:5000
You aren't returning anything from parsexml. Try returning some content:
#app.route('/', methods=['POST'])
def parsexml():
xmlrequest = xmltodict.parse(request.data)
print xmlrequest
return "Thanks for the data!"
Howdie do,
You can't send POST requests to /
So I changed it to go to the following:
__author__ = 'Jeremy'
from flask import Flask
from flask import request
import xmltodict
app = Flask(__name__)
#app.route('/')
def say_hello():
return "Say goodbye Jeremy"
#app.route('/api', methods=['POST'])
def parsexml():
xmlrequest = xmltodict.parse(request.data)
return xmlrequest
if __name__ == '__main__':
app.run(host='0.0.0.0', port=int("80"))
Work now

Categories