Edit incoming request body payloads in flask api - python

Im looking to make my Flask based API case insensitive for all incoming payloads. rather than having to apply this to all api-route functions i want to apply this to the #app.before_request decorator, such that for all incoming requests with json payloads (POSTs and PUTs) I directly edit the payload before it is handled by the applicable app.route function.
POST {"x":1, "Y":2} Should be formatted to POST {"x":1, "y":2} for request endpoints, but I can't seem to make this happen.
#app.before_request
def before_request():
if request.json:
data = RecusivelyLowerKeys(request.get_json())
request.data = json.dumps(ldata)
so far this approach hasn't worked and the original request payload seems static.
Any tips or alternative approaches would be appreciated thanks.

Related

Passing image to python FastAPI api endpoint

I'm quite new to apis and i have a problem. I want to use it to pass an image and process it. I thought just changing it to base64 will help and i will just pass a string to endpoint. But problem is that in base64 string there are '/' signs which break my url. Any ideas how i can fix it or there are any better ideas out there?
Code is simple:
app = FastAPI()
#app.get("/get_predictions/{base64_str}")
def get_predictions(base64_str: str):
return get_model_predictions(base64_str)
get_model_predictions just handles the image and return what it has to return
you can use UploadFile to pass files to your endpoint.
Here is an example:
from fastapi import FastAPI, File, UploadFile
#app.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
return {"filename": file.filename}
Be careful in my example I use the POST method and not GET.
I allow myself to offer you a solution with POST since you say you want to 'pass' an image, so this is done with a POST route and not GET
You can learn more by looking at this section of the documentation:
https://fastapi.tiangolo.com/tutorial/request-files/
Using get request for file transfer is a bad idea. Firstly you will have a giant url, secondly information you pass in get request may be exposed to other people.
The right solution is to use post request that will hide all the information in the request body. There you can transfer your images not only by using base_64 but also like multipart-formdata.
Here is the documentation to the Fast API post requests: post request or answer how to post an image using Fast API

Responding to an http request with JSON in Python

I have several Python scripts that are used from the CLI. Now I have been asked if I could provide a web API to perform some of the work normally done from the CLI. I would like to respond with JSON formatted data. I know little about JSON or API's.
How do I retrieve the query data from the http request?
How to a create the HTTP headers for the response from my script?
Given the following URL, how can I respond with a JSON reply of the name "Steve"?
http://myserver.com/api.py?query=who
I already have a functioning Apache web server running, and can serve up HTML and CGI scripts. It's simply coding the Python script that I need some help with. I would prefer not to use a framework, like Flask.
A simple code example would be appreciated.
The following is the Python code that I've come up with, but I know it's not the correct way to do this, and it doesn't use JSON:
#!/usr/local/bin/python3.7
import cgi # CGI module
# Set page headers and start page
print("Content-type: text/plain")
print("X-Content-Type-Options: nosniff\x0d\x0a\x0d\x0a")
# Form defaults
query_arg = None
# Get form values, if any
form = cgi.FieldStorage()
# Get the rest of the values if the form was submitted
if "query" in form.keys():
query_arg = form["query"].value
if query_arg == "who":
print("Steve", end="", flush=True)
You are trying to build a request handler with core python code. which is able to handle http request, In my opinion its not good idea as there are multiple securty scenarios attached with it, also in cross server request its bit difficult to handle all request and request scenarios . I will suggest to use Flask which is very lightweight and this will give an pre-setup of routing mechanism to handle all kind of request in very less code below is the snippet to generate http json response hope it helps
import sys
import flask
import random, string
from flask import jsonify
class Utils:
def make_response(self):
response = jsonify({
'message': 'success',
})
response.status_code = 200
return response

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

Redirect to a different URL only changing the domain name in flask

I am using Python flask. I have a POST request with some payload coming on say:
abc.com/hello/hello1
I want to redirect this (302) to:
xyz.com/hello/hello1
only changing the domain name while keeping the remaining part as it is and also the payload. Is there a simple way to do this?
As per RFC, redirect requests (all 3xx) cannot contain request data or headers. You will miss the payload, supplied via POST in original request.
There are two possible workaround I could think of right away:
Give the client new URL, and implement further logic on client side;
Create a proxy handler on backend, which will do a request by itself and give the answer back as it's own.
EDIT: As per Andrejs Cainikovs's comment below, this would not work for a POST with payload.
In your endpoint, get the url that was used using request.url (see request API here for more options). Then you can rewrite it and make a redirect.
newUrl = "xyz.com/" + route
return redirect(newUrl, code=302)

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.

Categories

Resources