Is HTTP Post blocked by Cloud9? - python

I've been playing around with Python/Flask on Cloud9 ide. Pretty fun so far. But when I try to add a http post to my test project, Flask returns either a 403 or a 500. From what I can tell, when I attach data or send the POST method, the 'request' object is None. It doesn't make sense though. This is pretty straight forward and should work as far as I can tell. Here's the python:
from flask import Flask, jsonify, abort, request
#app.route('/test', methods = ['POST'])
def post():
print ('started')
print request
if request.method == 'POST':
something = request.get_json()
print something
Flask is running correctly. I can hit a GET url, returning data just fine. I get an error when I land on 'print request' because request is None.
Thanks,

You have two problems here:
You're getting a 500 error
"something" is always None
The first problem is because you're not returning anything from your route function.
127.0.0.1 - - [15/Dec/2014 15:08:59] "POST /test HTTP/1.1" 500 -
Traceback (most recent call last):
...snip...
ValueError: View function did not return a response
You can remedy this by adding a return statement at the end of the function. Don't forget it needs to be a string.
#app.route('/hi', methods = ['POST'])
def post():
return "Hello, World!"
The second problem isn't what it seems. I suspect that the object isn't None, but the function that returns the string representation returns None, so that's what gets printed. Try print type(request) to see this in action.
What I think you want access to is the form field. Here is a complete example:
from flask import Flask, request
app = Flask(__name__)
#app.route('/test', methods = ['POST'])
def post():
print type(request)
if request.method == 'POST':
print request.form
return str(request.form)
app.run(debug=True)

Related

Setting a parameter in Post body to header when accessing Get endpoint in Flask?

I am working on a simple service with my show_greeting endpoint handling Get request while set_greeting is my Post.
The purpose of this app is that when "header_message: {header parameter}" is sent to set_greeting, {header parameter} will be returned in the header for responses to show_greeting and to reset {header parameter}, "clear" would reset header_message and header.
I have tried using global variables but encountered an error with shadowing from outside the scope and am not sure which approach to take for this. For now, I would like to learn how to return {header parameter} from my /show_greeting endpoint.
Edit: The /show_greeting endpoint returns holiday_message from the request. The header that I would like to send in addition to holiday_message is "header_message".
My code is as follows:
from flask import Flask, request, make_response, Response
app = Flask(__name__)
#app.route('/show_greeting', methods=['GET'])
def show_greeting():
received = request.args
(I do not know how to set header here from header_message in set_greeting)
return received['holiday_message']
#app.route('/set_greeting', methods=['POST'])
def set_greeting():
posted = request.args
if 'header_message' in posted:
(I attempted save_message = posted['header_message'] here but this approach failed)
return "Header Message Set"
else:
return "Please Send A Header Message"
if __name__ == '__main__':
app.run()
My recommendation is to use the session object. It stores the data in a cookie, which is sent with every request.
If a cookie is not desired, there are other options for saving sessions. For this, however, an extension will be necessary.
Saving with global variables should also work, but is not recommended.
A file or a database can also be used if the data is to be saved across multiple requests from many users.
The data of the post body can be accessed via request.form, while the url parameters of a get request can be queried via request.args.
from flask import Flask
from flask import request, session
app = Flask(__name__)
app.secret_key = b'your secret here'
#app.route('/show_greeting', methods=['GET'])
def show_greeting():
received = request.args
# get the saved message or an empty string if no message is saved
header_message = session.get('header_message', '')
return f"{received['holiday_message']} - {header_message}"
#app.route('/set_greeting', methods=['POST'])
def set_greeting():
posted = request.form
if 'header_message' in posted:
# store the message
session['header_message'] = posted['header_message']
return "Header Message Set"
else:
# clear the message
session.pop('header_message', None)
return "Please Send A Header Message"
Much success in your further steps.
If I understood your problem, you can work with "g" the flask global object.
Check this code, I expect it will fix your issue.
from flask import g # Added
from flask import Flask, request, make_response, Response
app = Flask(__name__)
#app.route('/show_greeting', methods=['GET'])
def show_greeting():
received = request.args
return g.saved_message # Modified
#app.route('/set_greeting', methods=['POST'])
def set_greeting():
posted = request.args
if 'message' in posted:
g.saved_message = posted['request'] # Added
return "Message Set"
else:
return "Please Send A Greeting Message"
if __name__ == '__main__':
app.run()

Flask - Pass back response of inner request

I looked at some of the similar suggested SO questions, but they weren't quite what I was looking for:
I have a Flask server with a POST route that calls another server. I want Flask to return the response from that request as-is.
import os
import requests
from flask import Flask, request, jsonify, make_response, Response
#app.route('/stuff', methods=['POST'])
def get_stuff():
resp = requests.post(...)
return resp
app.run(host='0.0.0.0', port=9999)
I've tried the following but each returns an error:
return jsonify(resp)
return ( resp.raw.read(), resp.status_code, resp.headers.items() )
return Response(json.dumps(resp), status=resp.status_code, mimetype='application/json')
I just want it to pass back what it got
Flask route functions should only return a string, you need a method to convert it and each of the attempts you made probably fell short in one way or another to do so.
Post the error messages, they may clue in how close you are to accomplishing the rerouting of the post response.

Flask Redirect Returns 200 Instead of 302

I'm writing unit tests for a Flask application and am not sure why the reponses are returning status code 200 instead of 302. The view I'm testing is using redirect and my post has follow_redirects=False set.
Below is the test and view code:
#test_views.py
def test_can_post_new_engagement(self):
response = self.client.post(
url_for('main.new_engagement'),
data={
'title': 'Sample Title',
'client': 1},
follow_redirects=False)
self.assertEqual(response.status_code, 302)
#views.py
#main.route('/engagement/new', methods=['GET', 'POST'])
def new_engagement():
form = EngagementForm()
form.client.choices = [(o.id, o.official_name) for o in
Organization.query.order_by('official_name')]
form.client.choices.insert(0, (0, '--- Select Organization ---'))
if form.validate_on_submit():
eng = Engagement(title=form.title.data,
client_id=form.client.data)
db.session.add(eng)
return redirect(url_for('main.new_pentest'))
return render_template('engagement_form.html', form=form)
Error:
FAIL: test_can_post_new_engagement (test_views.NewEngagementView)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/ramces/dev/global_engagement_manager/tests/unit/test_views.py
", line 36, in test_can_post_new_engagement
self.assertEqual(response.status_code, 302)
AssertionError: 200 != 302
Resolution
First, as Wombatz suggested, I didn't realize my form was not passing form.validate_on_submit().
After a little bit of debugging, I realized the CSRF token was missing from my testing configuration, so adding WTF_CSRF_ENABLED = False resolved this.
The flask redirect function does return a response with code 302
from flask import redirect
print(redirect("some_url").status_code) # 302
Your test is probably failing because your form validation fails.
Can you make sure that you are indeed entering the if-branch?
One problem could be that your client SelectField (assuming you are using wtforms) uses int as keys. Make sure that you provide coerce=int in the field's constructor.
I am using flask version 0.10.1
note: this should probably be a comment, but SO tells me i need 50 rep before commenting. But posting an answer is fine, of course.

Is it possible to make POST request in Flask?

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

Return HTTP status code 201 in flask

We're using Flask for one of our API's and I was just wondering if anyone knew how to return a HTTP response 201?
For errors such as 404 we can call:
from flask import abort
abort(404)
But for 201 I get
LookupError: no exception for 201
Do I need to create my own exception like this in the docs?
You can use Response to return any http status code.
> from flask import Response
> return Response("{'a':'b'}", status=201, mimetype='application/json')
You can read about it here.
return render_template('page.html'), 201
You can do
result = {'a': 'b'}
return result, 201
if you want to return a JSON data in the response along with the error code
You can read about responses here and here for make_response API details
As lacks suggested send status code in return statement
and if you are storing it in some variable like
notfound = 404
invalid = 403
ok = 200
and using
return xyz, notfound
than time make sure its type is int not str. as I faced this small issue
also here is list of status code followed globally
http://www.w3.org/Protocols/HTTP/HTRESP.html
Hope it helps.
In your flask code, you should ideally specify the MIME type as often as possible, as well:
return html_page_str, 200, {'ContentType':'text/html'}
return json.dumps({'success':True}), 200, {'ContentType':'application/json'}
...etc
Ripping off Luc's comment here, but to return a blank response, like a 201 the simplest option is to use the following return in your route.
return "", 201
So for example:
#app.route('/database', methods=["PUT"])
def database():
update_database(request)
return "", 201
you can also use flask_api for sending response
from flask_api import status
#app.route('/your-api/')
def empty_view(self):
content = {'your content here'}
return content, status.HTTP_201_CREATED
you can find reference here http://www.flaskapi.org/api-guide/status-codes/
In my case I had to combine the above in order to make it work
return Response(json.dumps({'Error': 'Error in payload'}),
status=422,
mimetype="application/json")
Dependent on how the API is created, normally with a 201 (created) you would return the resource which was created. For example if it was creating a user account you would do something like:
return {"data": {"username": "test","id":"fdsf345"}}, 201
Note the postfixed number is the status code returned.
Alternatively, you may want to send a message to the client such as:
return {"msg": "Created Successfully"}, 201
for error 404 you can
def post():
#either pass or get error
post = Model.query.get_or_404()
return jsonify(post.to_json())
for 201 success
def new_post():
post = Model.from_json(request.json)
return jsonify(post.to_json()), 201, \
{'Location': url_for('api.get_post', id=post.id, _external=True)}
You just need to add your status code after your returning data like this:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world(): # put application's code here
return 'Hello World!',201
if __name__ == '__main__':
app.run()
It's a basic flask project. After starting it and you will find that when we request http://127.0.0.1:5000/ you will get a status 201 from web broswer console.
So, if you are using flask_restful Package for API's
returning 201 would becomes like
def bla(*args, **kwargs):
...
return data, 201
where data should be any hashable/ JsonSerialiable value, like dict, string.

Categories