I'm working on a simple REST service with flask, the method deleteTweets() can't retrieve the URL parameter i'm sending, so tried to print to see what is sending but i get this error line.
File "C:\Path\HomeController.py", line 26, in deleteTwee
ts
id = request.args.get['id']
AttributeError: 'function' object has no attribute 'args'
127.0.0.1 - - [17/Jan/2018 12:00:05] "DELETE /api/deleteTweet?id=ABC HTTP/1.1" 500
This the code:
import json
import Service
from flask import Flask, render_template,jsonify,request
app = Flask(__name__)
apiUrl='/api'
#app.route('/')
def hello_world():
return render_template("/home.html", code=400)
#app.route(apiUrl+'/getData', methods=['GET'])
def test_request():
list = [15,21,8]
return jsonify(list)
#app.route(apiUrl+'/getTweets', methods=['GET'])
def request():
return Service.getAlltwits()
#app.route(apiUrl+'/deleteTweet', methods=['DELETE'])
def deleteTweets():
id = request.args.get['id']
print(id)
return
It's very simple but not sure what i did missed.
also tried with id = request.args.get('id')
You're doing the correct thing - and you're importing request.
But you have a function named request as well, and this function overwrites the former name (which is the actual flask request):
#app.route(apiUrl+'/getTweets', methods=['GET'])
def request():
return Service.getAlltwits()
Change the name to get_tweets instead:
#app.route(apiUrl+'/getTweets', methods=['GET'])
def get_tweets():
return Service.getAlltwits()
You've defined a function called request, which has therefore hidden the global request variable. Rename your route function.
Related
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()
I am trying to use flask-socket to request json from a client and want to return this object to the web. I try to print the object it is work in terminal but show null when I open local host. How can I fix this?
Or should I user socket in client to send message and get it in server?
Code for Server:
from flask import Flask, request, jsonify, Response
import json
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def add_message():
jsonData = request.get_json()
print(jsonData)
return jsonify(jsonData)
if __name__ == '__main__':
app.run(debug=True, host='127.0.0.1')
Code for Client:
import requests
while 1:
requests.post('http://127.0.0.1:5000/', json={"mytext": "lalala"})
I want the on the web can display the json data from my client side such as{"mytext":"lalala"} instead of null. My Output..
In addition, I want to pass a dynamic value from my client side and return it on the web. Thanks a lot!
In order to retrieve key-value pairs
For a GET request: you have to use request.args docs
For a POST request: you have to use request.get_json() docs
For a request to get a path parameter, you have to register your param as such docs
#app.route('/<name>', methods=['GET'])
def add_message_get_param(name):
print(name)
return jsonify({'name': name})
Now as you've stated, you want to pass a json. But your browser screenshot indicates that you call your endpoint with /hello. In order to pass a key-value pair, you'll have to do something like /?mykey=myvalue. I've added the path parameter for completeness
Thus, your server has to become
from flask import Flask, request, jsonify
app = Flask(__name__)
#app.route('/', methods=['GET'])
def add_message_get():
jsonData = request.args
print(jsonData)
return jsonify(jsonData)
#app.route('/<name>', methods=['GET'])
def add_message_get_param(name):
print(name)
return jsonify({'name': name})
#app.route('/', methods=['POST'])
def add_message_post():
jsonData = request.get_json()
print(jsonData)
return jsonify(jsonData)
if __name__ == '__main__':
app.run(debug=True, host='127.0.0.1')
and your client for debugging purposes:
import requests
result = requests.post('http://127.0.0.1:5000/', json={"mytext":"lalala"})
print(f'POST result: {result.text}')
result = requests.get('http://127.0.0.1:5000/?mytext=lalala')
print(f'GET result: {result.text}')
result = requests.get('http://127.0.0.1:5000/Antonis')
print(f'GET result: {result.text}')
Remove the .data from
return jsonify(jsonData).data
In my Flask application, I want to expose a URI like this:
http://<base_uri>/some_string
and I wish to handle requests to it differently depending on whether some_string is an integer or not.
With Sinatra I can achieve that via "passing" as shown below:
get '/:some_string' do
if is_integer(:some_string)
'Your URI contains an integer'
else
pass # This will pass the request on the the method below which can handle it
end
get '/*' do
'Your URI contains some string'
end
Here the call pass in the first route lets the second route process the request if :some_string is not an integer.
I couldn't find any equivalent functionality in Flask. Can someone please suggest a solution in Flask?
Type conversion in url routes can do this for you:
from flask import Flask
import unittest
app = Flask(__name__)
app.debug = True
#app.route('/<int:thing>')
def num(thing):
return 'INT'
#app.route('/<thing>')
def string(thing):
return 'STR'
class TestDispatch(unittest.TestCase):
def setUp(self):
self.client = app.test_client()
def test_int(self):
resp = self.client.get('/10')
self.assertEqual("INT", resp.data)
def test_str(self):
resp = self.client.get('/hello')
self.assertEqual("STR", resp.data)
if __name__ == '__main__':
unittest.main()
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
I have the following Flask routes and a custom helper:
from spots import app, db
from flask import Response
import simplejson as json
def json_response(action_func):
def create_json_response(*args, **kwargs):
ret = action_func(*args, **kwargs)
code = 200
if len(ret) == 2:
code = ret[0]
resp = ret[1]
else:
resp = ret[0]
return Response(
response=json.dumps(resp, indent=4),
status=code,
content_type='application/json'
)
return create_json_response
#app.route('/test')
#json_response
def test():
return 400, dict(result="Test success")
#app.route('/')
#json_response
def home():
return 200, dict(result="Home success")
I would expect a GET request to /test to return something like {"result":"Test success"} but that is not the case. Instead, any request seems to match the last route, i.e. home. Why?
I wonder if this is caused by some lack of insulation between the different calls to json_response?
Thanks in advance.
As Видул Петров said the solution is to use functools.wraps:
import functools
def json_response(action_func):
#functools.wraps(action_func)
def create_json_response(*args, **kwargs):
...
return create_json_response
The reason is that Flask’s routing system maps URLs to "endpoints", and then endpoints to view functions. The endpoint defaults to the __name__ attribute of the view function. In this case the decorated function was passed to app.route so the endpoint was create_json_response for both rules and the last view defined for that endpoint was used in both cases.
functools.wraps takes the __name__ (and other attributes) from the original function and fixes this. It is always a good idea to use it in decorated wrappers.