Handling variable Path Parameter in Python FastApi - python

I'm trying to write a simple get request for my Angular Frontend in FastApi
i've created this endpoint with the parameter of the item_id:
#app.get("/pokemon/{item_id}")
async def getPokemon(item_id: int):
response = pokemon.getPokemon()
return response
and in the getPokemon() i go to the official Api and make the get Request:
def getPokemon():
response = requests.get('https://pokeapi.co/api/v2/pokemon/{item_id}'),
pokemonOutput = json.loads(response.text)
return pokemonOutput
My Question is, if i make the request to my endpoint and send the item_id parameter from the frontend with it. How can i make it so the item_id is passed as variable in the url of the get Request to the official API?
I can't seem to find anything by googling.
Thx for helping!

you just modify the function
def get_pokemon(item_id):
response = requests.get('https://pokeapi.co/api/v2/pokemon/'+item_id),
pokemonOutput = json.loads(response.text)
return pokemonOutput
and call it from you're endpoint

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

Post Request as Media in MMS

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[]')

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.

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.

Categories

Resources