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()
Related
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.
I think this must be a really simple question or perhaps I'm overlooking something major, but I'm only getting started and there is something I just can't figure out.
I wrote a simple flask application:
from flask import Flask, request, jsonify
app = Flask(__name__)
#app.route("/")
def index():
return "Index!"
#app.route('/test', methods=['GET', 'POST'])
def test():
if request.method=='GET':
return "OK this is a get method"
elif request.method=='POST':
return "OK this is a post method"
else:
return("ok")
if __name__ == "__main__":
app.run()
When I open the following URL I get the GET method message as expected.
http://localhost:5000/test
But I can't switch it to a POST method.
What URL would I need to enter to see the POST method message?
Whenever you make a direct URL request via browser, it makes a GET call. It is not related to the URL, but the request type value that goes with the request to your server.
In order to make POST request (OR any other type of request) you may use any Rest Client Tool, refer: How do I manually fire HTTP POST requests with Firefox or Chrome?
Personally I use, Postman which comes as plugin for Chrome. Advance Rest Client is also a very nice alternative to achieve this.
If you want a geeky tool (some people consider command line to be geeky ;) ), you may use curl for transferring data with URLs. For making POST request, you have to call it as:
curl -i -X POST -H 'Content-Type: application/json' -d '{"param1": "value1", "param2": "value2"}' http://localhost:5000/test
HTML Forms are the primary way that you'd send a post request. Instead of your return "Index" you could instead do:
return '''
<form method="post" action="/test">
<input type="text" name="your field"/>
<button type="submit">Post to your /test!</button>
</form>
'''
In reality you'd have that form code in a whatever.html file within your template folder and render it with render_template to keep your code smart.
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.
I'm using FLASK API and I want to use POST requests.
I want just to do an example with POST requests that will return something, I keep getting an error message "Method Not Allowed".
I want to give a parameter(e.g query_params = 'name1' ) to search for a user and to return a JSON, actually I don't know where to give this parameter and I don't understand why I'm getting that message.
Here I did a simple route:
#mod_api.route('/show-user', methods=['POST'])
def show_user():
query_params = 'name1'
query = {query_params: 'Myname' }
json_resp = mongo.db.coordinates.find(query)
return Response(response=json_util.dumps(json_resp), status=200, mimetype='application/json')
Any help please?
The likely reason is that you are probably not doing a POST request against the route, which only accepts POST requests. Here is a simplified example with the mongodb details removed to illustrate this.
from flask import Flask
app = Flask(__name__)
#app.route('/show-user', methods=('POST',))
def show_user():
return "name info"
if __name__ == "__main__":
app.run(debug=True)
Now if we do a POST request it works, but if we do A GET request it raises the error you saw:
curl -H "Content-Type: application/json" -X POST -d '{}' http://127.0.0.1:5000/show-user
name info
curl -H "Content-Type: application/json" -X GET http://127.0.0.1:5000/show-user
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>
There is a need to make POST request from server side in Flask.
Let's imagine that we have:
#app.route("/test", methods=["POST"])
def test():
test = request.form["test"]
return "TEST: %s" % test
#app.route("/index")
def index():
# Is there something_like_this method in Flask to perform the POST request?
return something_like_this("/test", { "test" : "My Test Data" })
I haven't found anything specific in Flask documentation. Some say urllib2.urlopen is the issue but I failed to combine Flask and urlopen. Is it really possible?
For the record, here's general code to make a POST request from Python:
#make a POST request
import requests
dictToSend = {'question':'what is the answer?'}
res = requests.post('http://localhost:5000/tests/endpoint', json=dictToSend)
print 'response from server:',res.text
dictFromServer = res.json()
Notice that we are passing in a Python dict using the json= option. This conveniently tells the requests library to do two things:
serialize the dict to JSON
write the correct MIME type ('application/json') in the HTTP header
And here's a Flask application that will receive and respond to that POST request:
#handle a POST request
from flask import Flask, render_template, request, url_for, jsonify
app = Flask(__name__)
#app.route('/tests/endpoint', methods=['POST'])
def my_test_endpoint():
input_json = request.get_json(force=True)
# force=True, above, is necessary if another developer
# forgot to set the MIME type to 'application/json'
print 'data from client:', input_json
dictToReturn = {'answer':42}
return jsonify(dictToReturn)
if __name__ == '__main__':
app.run(debug=True)
Yes, to make a POST request you can use urllib, see the documentation.
I would however recommend to use the requests module instead.
EDIT:
I suggest you refactor your code to extract the common functionality:
#app.route("/test", methods=["POST"])
def test():
return _test(request.form["test"])
#app.route("/index")
def index():
return _test("My Test Data")
def _test(argument):
return "TEST: %s" % argument