Post Request as Media in MMS - python

I wrote a python program that gets a photo from a webserver. The photo is obtained by sending a POST request to my URL (the returned photo depends on data of POST request):
myobj = {'x': [1,2,3,4], 'y': [1,2,3,6]}
x = requests.post('http://cainevisualizer.azurewebsites.net/plot.png', data=myobj)
x is a requests.Response object with methods giving its content, status code, the response url, the text (in unicode) etc (see all methods here. However, it appears that, in order to send a text message of an image in Twilio, Message().media requires the URL of the image.
message = Message()
message.media(myURL)
Again, the webserver (in Flask) returns an image after a post request rather than returning a unique url to the image. Is there an API or some other way to convert a MIME image into a unique url? Any advice appreciated.

I think I found a solution to my own question. So, I changed the webserver that hosts the photo to now accept GET requests. I then pass my parameters to and send a GET request to the webserver. See the GET request as follows:
import requests
data = {'x[]': [1,2,3,4], 'y[]': [4,5,6,7]}
response = requests.get('http://cainevisualizer.azurewebsites.net/plot.png', params=data)
url = response.url
This request passes the parameters in the data dictionary as a single URL to the webserver. In this case, the GET request is encoded as a url and passes [1,2,3,4] and [4,5,6,7] as query parameters. This is instead of sending the information in the GET request as part of the body of the request (or as part of anything BUT the url itself)
I now use the request.args.getlist('x[]') and request.args.getlist('y[]') function in the webserver to to get the information from this GET request... it looks something like this
from flask import Flask, request, make_response
app = Flask(__name__)
#app.route('/plot.png', methods=['GET', 'POST'])
def plot():
xs = request.args.getlist('x[]')
ys = request.args.getlist('y[]')

Related

How to send POST request using flask.redirect?

I'm trying to create a flask service in which I want to send the data coming from one request.form to another url in json format, Please can anyone help me to achieve this?
redirect(url_for('any_method'), json = json.dumps(my_form_dict))
When I try to execute the above code I'm getting following error:
TypeError: redirect() got an unexpected keyword argument 'json' The above is the error here.
You can redirect POST requests using 307 status code.
Use:
redirect(url_for('any_method', json=json.dumps(my_form_dict)), code=307)
For more information refer to this answer:
Make a POST request while redirecting in flask
It is not possible to redirect POST requests.
More info is here.
Your problem is that you are passing too much arguments to the redirect function. It only expects three parameters, location, code, and Response. If you want to pass extra parameters, use the Flask url_for method:
redirect(url_for('any_method', json=form_json))
Note the difference, you were passing the url_for and extra fields as two parameters. In my version, I've added the extra fields in the url_for, so redirect only receives one parameter.
I used the requests package to redirect a GET request to the POST one.
The trick is using flask.make_response() to make a new Resposne object.
In my scenario, the last response is an HTML text, so I get text as a response.
from flask import request, make_response
import requests
#app.route('/login', methods=['GET'])
def login():
data = {"data": request.args['data']}
redirect_response = requests.post('https://my-api/login', json=data).text
return make_response(redirect_response, 302)

Python Requests Programmatically get Dev Tools Form Data pre-formatted as a dictionary

I am trying to update an already saved form on a system using HTTP requests. Due to the server configuration for the third party app we use, updating by POST requires sending a fully filled out payload every single time.
I want to get round this by recovering the form data already present on the server and converting it into a dictionary. Then changing any values I need and reposting to make changes sever side.
The application we use sends a POST request when the save button is clicked for a particular form.
Here I send a post request with no payload.
[This simulates pressing the save button and is also the point where dev tools shows me a the payload I want to capture]
post_test = self.session.post(url_to_retrieve_from)
I thought that now I should be able to print the output, which should resemble what Google Dev tools Form data captures.
print(post_test.text)
This just gives me html found on the webpage.
If Dev Tools can get this from the server then I should also be able to?
Example of Data I am trying to get via requests:
Form Data
If Dev Tools can get this from the server then I should also be able to?
Yes, of course. In requests you pass form data in data keyword:
import requests
url = 'http://www.example.com'
data = {
'name': 'value',
}
response = requests.post(url, data=data)
You can get the data you sent with a request from the response in this way:
import requests
response = requests.post('http://your_url', data=data) # send request
body = response.request.body
parsed_data = dict(data.split('=') for data in body.split('&')) # parse request body
Here you can find more information about data argument
In the documentation, in the class requests.Response we can find the attribute:
request = None
The PreparedRequest object to which this is a response.
In requests.PreparedRequest class we can read:
body = None
request body to send to the server.

Returning response of Tornado POST request

I have seen Tornado documentations and examples where self.write method is widely used to render some value on HTML, where the POST request was run in a handler. But I could not find much clarity on how to return the response back to client.
For example, I am calling a POST request on a Tornado server from my client. The code that accepts post request is:
class strest(tornado.web.RequestHandler):
def post(self):
value = self.get_argument('key')
cbtp = cbt.main(value)
With this, I can find the value of cbtp and with self.write(cbtp), I can get it printed in HTML. But instead, I want to return this value to the client in JSON format, like {'cbtp':cbtp}
I want to know how to modify my code so that this response is sent to the client, or give me some documentation where this this is fluently explained.
Doing something like
res = {cbtp: cbtp}
return cbtp
throws a BadYieldError: yielded unknown object
You just need to set the output type as JSON and json.dumps your output.
Normally I have the set_default_headers in a parent class called RESTRequestHandler. If you want just one request that is returning JSON you can set the headers in the post call.
class strest(tornado.web.RequestHandler):
def set_default_headers(self):
self.set_header("Content-Type", 'application/json')
def post(self):
value = self.get_argument('key')
cbtp = cbt.main(value)
r = json.dumps({'cbtp': cbtp})
self.write(r)
If the given chunk is a dictionary, we write it as JSON and set the Content-Type of the response to be application/json. (if you want to send JSON as a different Content-Type, call set_header after calling write()).
Using it should give you exactly what you want:
self.write(json.dumps({'cbtp': cbtp}))

How to use flask request properly to retrieve data from JSON?

I looked many questions similar to my title but I have not found any that had same problem as me yet.
I did requests.post to post JSON to API restful server. Below is the snippet
import requests
def upload_data():
url = "http://127.0.0.1:8088/"
data = {"value":"abc123"}
response = requests.post(url, data=data)
print response.status_code, response.reason, response.text
upload_data()
And for the server side
from flask_restful import Api, Resource
from flask import request
class MyAPI(Resource):
def get():
pass
def post(self):
value = request.data['value']
response_object = {
'value':value
}
return response_object, 201
I was hoping to get the POST function to work by showing the result of 201 Created with
{
'value':'abc123'
}
But whenever I run the script, it gives me error saying that
value = request.data["value"]
TypeError: string indices must be integers, not str
I am sorry if this is a bad question but if anyone could show me what I have been missing in this script, I really appreciate it. Thank you.
That's because request data hasn't been parsed into a python dictionary. Were you perhaps thinking of
data = json.loads(request.data)
However please note that you are not actually posting a JSON body to your flask server. You are posting multipart formdata. So you may probably be looking for the answer posted by luoluo.
One the other hand if you really wanted to deal with json, The correct way to send json looks something like this:
requests.post(url, json=data)
And then the loads as suggested.
The request.data is a string, while request.values is a MultiDict.
You need update your code to :
value = request.values.get('value')
instead of
value = request.data['value']
According to the doc
args
A MultiDict with the parsed contents of the query string. (The part in the URL after the question mark).
form
A MultiDict with the parsed form data from POST or PUT requests. Please keep in mind that file uploads will not end up here, but instead in the files attribute.
values
A CombinedMultiDict with the contents of both form and args.
data
Contains the incoming request data as string in case it came with a mimetype Flask does not handle.

Make request to Flask view from Flask-Script command

I have a Flask view that returns some JSON data and want to get that same data in a Flask-Script command. I was going to use the Requests library but don't know what URL to use without hard-coding the host. How can I get the JSON data returned by the view?
#manager.command
def showdata():
data = requests.get('/data-page') # fails, needs full URL
print(data.json())
When you're in your code, you don't need to make an external request. Use the test_client to make a request.
c = app.test_client()
r = c.get('/data-page')
data = json.loads(r.get_data(as_text=True))
print(data)
Ideally, extract the logic from the presentation in the view and just call a function rather than making any request at all.
# command
print(get_data())
# view
return jsonify(get_data())

Categories

Resources