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
Related
I'm updating some APIs that I have coded using Python and FastAPI. In the actual version I'm sending the info using Query Paramenters, but now I want to try to send the data by using Request Body, but the code doesn't seem to work.
Below you can see a sample of the code on the Server Side where FastAPI should return the text I'm sending (for this example only the "string_to_show" info, but in the real project there would be more fields). I know that is a base code, but this is just a sample.
from fastapi import FastAPI, Path, Query
from pydantic import BaseModel
import uvicorn
app = FastAPI()
class req_body(BaseModel):
string_to_show:str
#app.get("/test/")
def scraper_shield(payload:req_body):
request_feedback = str(payload.string_to_show)
return request_feedback
if __name__ == "__main__":
uvicorn.run(app)
On the Client Side I'm using this code, that simply sends the payload to the server.
import requests
payload = {'string_to_show':'Python is great!'}
r = requests.get('http://127.0.0.1:8000/test/', params=payload)
print(r.text)
When sending the request, I should get the string "Python is Great!" but instead I'm getting some errors, below the Client and Server messages:
CLIENT: {"detail":[{"loc":["body"],"msg":"field required","type":"value_error.missing"}]}
SERVER: "GET /test/?string_to_show=Python+is+great%21 HTTP/1.1" 422 Unprocessable Entity
GET methods are not suppose to have body.
https://dropbox.tech/developers/limitations-of-the-get-method-in-http
POST method is meant for that.
If you really need some robust parametrization with GET (but I really would reconsider that), think about putting them into custom header(s).
You are sending the parameters as query strings when using
r = requests.get('http://127.0.0.1:8000/test/', params=payload). You have to instead use
r = requests.get('http://127.0.0.1:8000/test/', json=payload) which will create a request body and send it correctly. This what you also see from the errors, which basically tell you that the required body is missing.
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)
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.
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.
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.