Returning response of Tornado POST request - python

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}))

Related

Can't access or print any request data with FastAPI

I have a simple FastAPI endpoint, where I want to receive a string value. In this case, I tried it with a JSON body, but basically it doesn't need to be JSON. I really need only a simple string to separate the requests from each other. Unfortunately, I can't access any of the request parameters with a GET method. I also tried POST method instead, but I get an error:
request:
url = "http://127.0.0.1:5000/ping/"
payload=json.dumps({"key":"test"})
headers = {
"Content-Type": "application/json"
}
response = requests.request("POST", url, headers=headers, json=payload)
print(response.text)
api:
#app.get("/ping/{key}")
async def get_trigger(key: Request):
key = key.json()
test = json.loads(key)
print(test)
test2 = await key.json()
print(key)
print(test2)
return
I can't print anything with post or put:
#app.post("/ping/{key}")
async def get_trigger(key: Request):
...
or
#app.put("/ping/{key}")
async def get_trigger(key: Request):
I get a 405 Method not allowed error.
How can I get this fixed?
The 405 Method Not Allowed status code indicates that "the server knows the request method, but the target resource doesn't support this method". You get this error when you attempt, for instance, to send a POST request to a GET route (as shown in your first example). This, however, is not the only issue with your code (on both client and server sides). Below is given an example on how to achieve what you described in the question using Path parameters. The same could be achieved using Query parameters, as well as Request Body. Please have a look at Python requests documentation on how to specify the parameters/body for each case. I would also highly suggest to take the FastAPI tutorial online—you'll find most of the answers you are looking for there.
app.py
from fastapi import FastAPI
app = FastAPI()
#app.get("/ping/{ping_id}")
async def get_trigger(ping_id: str):
return {"ping_id": ping_id}
test.py
import requests
url = 'http://127.0.0.1:8000/ping/test1'
resp = requests.get(url=url)
print(resp.json())

How to mock http calls in the execution of UT, and return actual response to actual flow in python

I have created a an application in python-django, where it makes some api call to some 3rd party services and then return response, post that I am doing some processing on response data and generating some final document. Below is something I am doing:
def get_processed_data(url, payload, tenant, req_id, timeout=None):
query_kwargs = HTTPRequestUtils.__get_query_kwargs(timeout)
query_kwargs['json'] = payload
response = HTTPRequestUtils.__get_response(url, query_kwargs, requests.post)
.....
data=process_response(response)
return more_processings(data)
Abobe is one of the function , being called during actual execution of code. And response varies with url.
Now problem is I have am writing Unit Test , and i have to emulate/mock http call, so that for different url, i may return different mocked response, that will be further processed.
I went through several libraries like responses etc, but what I conclude from them is , i can test just api call and its returned response. But in actual I need to just emulate/mock http call for different and return response back, like we do in patch during mock, so that the response can be further go for processing.
Any library or method by which we can achieve this.
If you have an idea of order in which the API call would take place, you can make use of side-effect func of mock library, so what it does is it will give different response for each time the mock function is called
for eg:
mock_api.side_effect = [(resp1),(resp2)]
so when api() will be called for the 1st time => response will be resp1 and for the second time ==> response will be resp2
I think this will solve your problem

Check the Integrity of Message to an API Response message using JWT-extended in Flask

Assuming that I have an API endpoint api.example.com/v1/data and a GET method with #jwt-required similar to this:
from flask_jwt_extended import jwt_required
from flask_restful import Resource
class Data(Resource):
#jwt_required
def get(self):
"""
GET Response message.
"""
return {"message":"important-info", "ts":datetime}, 200
So to GET this message you need to authenticate yourself with a Bearer "access_token" in the request's header.
How could I create an HMAC for this message. Ideally I would like to add the access token, so to check the integrity of the whole message.
So I would like to have an extra field in the returned JSON called checksum with a value hash(whole_message).
You can use Flask's after_request to register a function that processes the response after it was generated by the view.
For example, to do exactly what you ask for (I am using built-in python's hash function, you can import/write your own as needed):
#app.after_request
def after_request(response):
data = json.loads(response.get_data())
data['checksum'] = hash(response.get_data())
response.set_data(json.dumps(data))
return response
However, you will have to make sure to always return a dictionary for this to work. Here are a couple alternatives:
1) Include the view's response inside another json, e.g.:
#app.after_request
def after_request(response):
data = json.loads(response.get_data())
data = {
'response': data,
'checksum': hash(response.get_data())
}
response.set_data(json.dumps(data))
return response
2) Add the checksum to the response headers (I would go with this one). E.g.:
#app.after_request
def after_request(response):
response.headers['Checksum'] = hash(response.get_data())
return response
As a final note, if you want to hash the response using the access token, as you state in your question, you can access this token from the request object, like so:
from flask import request
access_token = request.headers.get('Authorization')
So now you can use access_token in whatever way you need.

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.

Flask-RESTful: Using GET to download a file with REST

I am trying to write a file sharing application that exposes a REST interface.
The library I am using, Flask-RESTful only supports returning JSON by default. Obviously attempting to serve binary data over JSON is not a good idea at all.
What is the most "RESTful" way of serving up binary data through a GET method? It appears possible to extend Flask-RESTful to support returning different data representations besides JSON but the documentation is scarce and I'm not sure if it's even the best approach.
The approach suggested in the Flask-RESTful documentation is to declare our supported representations on the Api object so that it can support other mediatypes. The mediatype we are looking for is application/octet-stream.
First, we need to write a representation function:
from flask import Flask, send_file, safe_join
from flask_restful import Api
app = Flask(__name__)
api = Api(app)
#api.representation('application/octet-stream')
def output_file(data, code, headers):
filepath = safe_join(data["directory"], data["filename"])
response = send_file(
filename_or_fp=filepath,
mimetype="application/octet-stream",
as_attachment=True,
attachment_filename=data["filename"]
)
return response
What this representation function does is to convert the data, code, headers our method returns into a Response object with mimetype application/octet-stream. Here we use send_file function to construct this Response object.
Our GET method can be something like:
from flask_restful import Resource
class GetFile(Resource):
def get(self, filename):
return {
"directory": <Our file directory>,
"filename": filename
}
And that's all the coding we need. When sending this GET request, we need to change the Accept mimetype to Application/octet-stream so that our API will call the representation function. Otherwise it will return the JSON data as by default.
There's an xml example on github
I know this question was asked 7 years ago so it probably doesn't matter any more to #Ayrx. Hope it helps to whoever drops by.
As long as you're setting the Content-Type header accordingly and respecting the Accept header sent by the client, you're free to return any format you want. You can just have a view that returns your binary data with the application/octet-stream content type.
After lot of trials and experiments, including hours of browsing to make the Response class as Single Responsible down loader
class DownloadResource(Resource):
def get(self):
item_list = dbmodel.query.all()
item_list = [item.image for item in item_list]
data = json.dumps({'items':item_list})
response = make_response(data)
response.headers['Content-Type'] = 'text/json'
response.headers['Content-Disposition'] = 'attachment; filename=selected_items.json'
return response
Change your filename and content type to support the format you want.

Categories

Resources