Axios POST is not parsed correctly in Python Flask - python-3.x

Intro
Hi, I can see this question asked multiple times, but not a proper solution.
whats wrong
GET requests are working as expected. but if I use Vue.js and Axios to send a POST request to a flask server.
POST with JSON sent with Postman also works..
heres the axios call:
async submit() {
await this.$axios.post("/bob/posting", { foo: "bar" }).then(response => {
console.log(response)
})
}
On the flask side:
from flask import Flask, request
from flask_cors import CORS,cross_origin
app = Flask(__name__)
cors = CORS(app, resources={r"//*": {"origins": "*"}})
#app.route('/bob/posting', methods=['POST'])
def handleRoute():
print(request.is_json)
return (
request.args
or request.form
or request.get_json(force=True, silent=True)
or request.data
)
The results at the flask side:
True will be printed (indicating a json request)
nothing will be returned (also, for each option I tried printing it individually just in case)
Q
How can I properly use variables received from an axios json request on a flask server?

Did not at all understand why, but adding a text/plain content type fixed it.. what...
async submit() {
await this.$axios.post("/bob/posting", { foo: "bar" }, {'content-type':'text/plain'}).then(response => {
console.log(response)
})
}

Related

Forwarding a request to another API in Python (Rust) Robyn

I am using FastAPI to take in a JSON file which will then be the body of an API request out.. Orwell and Good so far. Now I want to apply the same but with robyn built on rust, instead of FastAPI. Not managed to get any joy with calling the API here at the point marked ??.
What things do I need to consider (documentation is sparse). Does robyn cut it alone, or am I missing something?
from robyn import Robyn, jsonify
app = Robyn(__file__)
#app.post("/yt")
async def json(request):
body = request["body"]
outurl = "https://translate.otherapi.com/translate/v1/translate"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer {0}".format(TOKEN)
}
?? response_data = await call_api(data)
return response_data['translations'][0]
app.start(port=5000)
With FastAPI:
import aiohttp
import aiofiles
import json
import requests
from fastapi import FastAPI, Header, Depends, HTTPException, Request
app = FastAPI()
async def call_api(data):
async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=False)) as session:
async with session.post(url, headers=headers, json=data) as resp:
response_data = await resp.json()
return response_data
#app.post("/yt")
async def root(request:Request):
data = await request.json()
file_path = "data.json"
await write_json_to_file(data, file_path)
data = await read_json_from_file(file_path)
response_data = await call_api(data)
return response_data['translations'][0]
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8001)
The author of Robyn here. I am unable to understand what you are trying to achieve here. However, there is one issue, request["body"] returns a byte string array at the moment.
You need to alter your code to this:
import json
#app.post("/yt")
async def json(request):
body = bytearray(request["body"]).decode("utf-8")
data = json.loads(body)
outurl = "https://translate.otherapi.com/translate/v1/translate"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer {0}".format(TOKEN)
}
response_data = await call_api(data)
return response_data['translations'][0]
This is peculiarity that I am not very fond of. We are hoping to fix this within the next few releases.
I hope this helped :D

serve webpage using hypercorn (without any framework)

The code in the documentation is:
A very simple ASGI app that simply returns a response containing hello is, (file hello_world.py)
async def app(scope, receive, send):
if scope["type"] != "http":
raise Exception("Only the HTTP protocol is supported")
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
(b'content-type', b'text/plain'),
(b'content-length', b'5'),
],
})
await send({
'type': 'http.response.body',
'body': b'hello',
})
simply run via
hypercorn hello_world:app
But the problem is, i do not want to handle type, status or headers.
I can do it with fastapi. Here, i do not need to handle type, status or headers. Given the file name is hello_world.py
from fastapi import FastAPIapp = FastAPI()
#app.get("/")
async def root():
return {"message": "Hello world!"}
simply run using
hypercorn hello_world:app
How can I have this fastapi like behaviour without fastapi. I mean is there any simple http parser which i can use instead of fastapi. Custom code would be even better.

Trying to get 2 values returned from async aiohttp get call

Today I was trying to speed up my script and found great example code from another stackoverflow post. Basically I found a way to make async requests using aiohttp to web instead of using requests. Here is the link to that post (I copied code from DragonBobZ's answer).
Link to other stackoverflow post from which I copied code
The issue is that I am trying to get it to return 2 values (url, response) instead of just the response from the request made. Here is the code I took.
def async_aiohttp_get_all(urls, cookies):
async def get_all(urls):
async with aiohttp.ClientSession(cookies=cookies) as session:
async def fetch(url):
async with session.get(url) as response:
return await response.json()
return await asyncio.gather(*[
fetch(url) for url in urls
])
return sync.async_to_sync(get_all)(urls)
for x in async_aiohttp_get_all(urls_list, s.cookies.get_dict()):
print(x)
Now I am successfully able to get responses from all urls within fraction of time it was taking with requests but I want the function to also return the url with:
return await response.json()
I tried this but nothing works and this is my first day to ever use async practices in python so I am not even able to search for a solution as nothing makes sense.
return await url, response.json()
return await (url, response.json())
I could not run the code exactly how you do, but I returned a tuple with no problem. Also removed the sync call, since asyncio gives you enough flexibility.
import asyncio
import aiohttp
urls_list = [
"https://www.google.com",
"https://www.facebook.com",
"https://www.twitter.com",
]
async def async_aiohttp_get_all(urls, cookies):
async with aiohttp.ClientSession(cookies=cookies) as session:
async def fetch(url):
async with session.get(url) as response:
return await response.text(), url
return await asyncio.gather(*[
fetch(url) for url in urls
])
results = asyncio.run(async_aiohttp_get_all(urls_list, None))
for res in results:
print(res[0][:10], res[1])
Output:
<!doctype https://www.google.com
<!DOCTYPE https://www.facebook.com
<!DOCTYPE https://www.twitter.com
So, in your case, return await response.json(), url should work.

Get content-length of FastAPI response

Im trying to get the content-length of FastAPI response on the server side for logging purpose. Is this possible? Thanks.
#app.get("/foo")
async def foo(background_tasks: BackgroundTasks):
data = {"foo": "foo"}
response_content_length = get_content_length()
background_tasks.add_task(log, response_content_length )
return data
You can create your own route by inheriting APIRoute class, now you should be able to log everything, without repeating yourself.
from fastapi import FastAPI, Request, Response, Body, BackgroundTasks, APIRouter
from fastapi.routing import APIRoute
from typing import Callable, List
class ContextIncludedRoute(APIRoute):
def get_route_handler(self) -> Callable:
original_route_handler = super().get_route_handler()
async def custom_route_handler(request: Request) -> Response:
response: Response = await original_route_handler(request)
content_length = response.headers["content-length"]
print(content_length)
return response
return custom_route_handler
app = FastAPI()
router = APIRouter(route_class=ContextIncludedRoute)
#router.post("/dummy")
async def dummy():
return {"foo":"foo"}
app.include_router(router)

Facebook messenger chatbot with Flask and pymessenger

I have created a messenger chatbot with flask, pymessenger and wit.ai.
I want to add facebook provided templates (like buttons, adding images and sound media)(https://developers.facebook.com/docs/messenger-platform/reference/template/button/)
There using some curl and json thing which I do not understand. Can some one help me, where should I put these snippet in my python code.
#app.route('/', methods=['POST'])
def webhook():
data = request.get_json()
log(data)
if data['object'] == 'page':
for entry in data['entry']:
for messaging_event in entry['messaging']:
sender_id = messaging_event['sender']['id']
recipient_id = messaging_event['recipient']['id']
if messaging_event.get('message'):
if 'text' in messaging_event['message']:
messaging_text = messaging_event['message']['text']
else:
messaging_text = 'no text'
response = None
entity, value = wit_response(messaging_text)
if entity == 'newstype':
response = "OK. I will send you {} news".format(str(value))
elif entity == 'cust_greet':
response = get_message()
elif entity == 'cust_bye':
response = "Bye! Have a Good Day!".format(str(value))
elif entity == 'cust_option':
response = "Option 1: Option 2:"
bot.send_text_message(sender_id, response)
return "ok", 200
def log(message):
print(message)
sys.stdout.flush()
HTTP requests use one of these two formats:
GET: All the request information is in the url
POST: Some information is sent via a JSON format to the url
What we see in the Facebook API is a POST request: the url is defined as
https://graph.facebook.com/v2.6/me/messages?access_token=<PAGE_ACCESS_TOKEN>
...and there is POST request information in the JSON section underneath
Curl is a program used to send HTTP requests from the terminal. If you install Curl, you can fill in the JSON/url information, run the command (which sends the POST request), and see the buttons pop up for the recipient. Just as you want your chatbot to do!
However, Curl is a tool, not a Python library!
To do this in Python, you can send the request through Python's built in libraries, or install a package which makes this easier (such as requests), look into "sending http requests via python".
Below is an example (adapted from this question):
from urllib.parse import urlencode
from urllib.request import Request, urlopen
# the url we are sending the request to
url = "https://graph.facebook.com/v2.6/me/..."
# the POST request data
request_data = {
"recipient": {
"id": "<PSID>"
},
"message": {
"attachment": {
...
}
}
}
# create the request with the url and the data
post_request = Request(url, urlencode(request_data).encode())
# send it to Facebook! Response is the API response from Facebook
response = urlopen(post_request).read().decode()

Resources