FastAPI and Flask response issue - python

I've below code of Flask calling FastAPI end point. But the response not getting generated(Error: 422) when the FastAPI end point is being invoked and FastAPI end point log says INFO:127.0.0.1:56904 - "POST /runquery HTTP/1.1" 422 Unprocessable Entity
Inputs to FASTAPI end point
query : select c2,c2,c4,c5 from table_tab
env= iAT
Flask Code
import requests
app = Flask(__name__)
#app.route("/", methods=["GET", "POST"])
def index():
query_id = ""
query = ""
status = ""
env = ""
if request.method == "POST":
query = request.form["query"]
env = request.form["env"]
data = {"query": query, "env": env}
print(data)
headers = {'Content-Type': 'application/json'}
**response = requests.post("http://localhost:8000/runquery", json=data,headers=headers)**
print(response)
if response.status_code != 200:
return f'Error: {response.status_code}'
else:
print(response.json())
response_data = response.json()
query_id = response_data["query_id"]
status = response_data["status"]
return render_template("index.html", query_id=query_id, query=query, status=status, env=env)
if __name__ == "__main__":
app.run(debug=True) ```
**Here is the FastAPI end point code**
``` #app.post("/runquery")
async def runquery(query: str, env: str):
print('.....')
delay = 60
parsed_query = sqlparse.parse(query)[0]
if parsed_query.get_type() == "SELECT":
pass
else:
return JSONResponse(content={"error": "Only SELECT queries are allowed"}, status_code=422)
# return {"error": "Only SELECT queries are allowed"}
registry_scheduled = ScheduledJobRegistry(queue=que)
registry_started = StartedJobRegistry(queue=que)
# registry_completed = FinishedJobRegistry(queue=que)
# registry_failed = FailedJobRegistry(queue=que)
if len(registry_scheduled.get_job_ids()) >= 2:
return JSONResponse(content={"Info": "GQs are already in-progress. Try after some time"})
# return {"Info": "GQs are already in-progress. Try after some time"}
if len(registry_started.get_job_ids()) >= 2:
return JSONResponse(content={"Info": "GQs are already in-progress.Try after some time"})
# return {"Info": "GQs are already in-progress.Try after some time"}
# Generate a unique ID for the query
query_id = str(uuid.uuid4())
print('query_id..........', query_id)
directory_path = os.path.join(home_path, query_id)
print(directory_path)
if not os.path.exists(directory_path):
os.makedirs(directory_path)
file_path = os.path.join(directory_path, "query.sql")
with open(file_path, "w") as f:
f.write(query)
# job = que.enqueue(exec_query, query, env, sqlfile)
job = que.enqueue_in(timedelta(seconds=delay), exec_query, query, env, query_id)
r.set(query_id, job.id)
# Return the query ID to the user
return JSONResponse(content={"query_id": query_id, "query": query, "stauts": "OK"},
status_code=202) ```

422 is Unprocessable Entity, it means that your request sent has wrong format parameter in the body. You must use Pydantic class to validate json.
Change FastAPI endpoint in this way :
from pydantic import BaseModel
class Data(BaseModel):
query: str
env: str
#app.post("/runquery")
async def runquery(data: Data):
...

Related

How can I make my API request working via Postman?

I am working with Postman for the first time and GET request to my simple API is working fine, but when I try POST request it gives me an error and I have no idea where is the problem. Can you please advise?
API function:
#app.route('/customer', methods=['POST'])
def create_customer():
request_data = request.get_json()
new_customer = {
"email": request_data['email'],
"username": request_data['username'],
"name": request_data['name'],
"newsletter_status": request_data['newsletter_status'],
"trips": []
}
for customer in customers:
if customer['username'] == new_customer['username']:
return jsonify({'error': 'username already exist'})
customers.append(new_customer)
return jsonify(new_customer)
Screenshots from postman
This I put in the body + error message
Headers set up - Content-Type application/json
I think your new customer variables should not be in string format, I don't know why they are and also try my option for getting the request body:
import json
def create_customer():
request_data = json.loads(request.body)
new_customer = {
email = request_data['email'],
username = request_data['username'],
name = request_data['name'],
newsletter_status = request_data['newsletter_status'],
trips: []
}
for customer in customers:
if customer['username'] == new_customer['username']:
return jsonify({'error': 'username already exist'})
customers.append(new_customer)
return jsonify(new_customer)
Yur code works fine , i just tested with postman:
from flask import jsonify
from flask import Flask
from flask import request
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello, World!'
#app.route('/customer', methods=['POST'])
def create_customer():
customers=[]
customers.append(request.get_json())
request_data = request.get_json()
new_customer = {
"email": request_data['email'],
"username": request_data['username']+"HHH",
"name": request_data['name'],
"newsletter_status": request_data['newsletter_status'],
"trips": []
}
print(new_customer['username'])
print(customers[0]['username'])
for customer in customers:
if customer['username'] == new_customer['username']:
return jsonify({'error': 'username already exist'})
customers.append(new_customer)
return jsonify(new_customer)
Can you check what is exactly send in postman ?
you can do it by clicking console ( can get from left botom corner or by pressing ctrl+alt+c ) >request > requestbody

Pytest Flask post return 'Response' object has no attribute 'items'

I'm working on a project using Python(3.7) and Falsk, in which I'm implementing testing for my API. For a POST request, when I submit the request client using test_client with the proper payload it returns an error as:
AttributeError: 'Response' object has no attribute 'items'
Here's what I have done so far:
From view function:
if request.method == "POST":
data = request.get_json()
new_author = data['author']
new_title = data["title"]
new_sDescription = data["shortDescription"]
new_Url = data["thumbnailUrl"]
new_status = data["status"]
new_pageCount = data["pageCount"]
....
if None not in (new_author, new_title, new_Url, new_status, new_pageCount
, new_sDescription):
return f"Book with the id: {cursor.lastrowid} created successfully", 201
** Test Fixture:**
#pytest.fixture
def client():
app.config['TESTING'] = True
db_fd, app.config['DATABASE'] = tempfile.mkstemp()
with app.test_client() as client:
with app.app_context():
create_table(app.config['DATABASE'])
yield client
** Function to send request:**
def api_post_book(client):
payload = {
"author": "Someone",
"pageCount": 590,
"shortDescription": "A book from PyTest.",
"status": "PUBLISH",
"thumbnailUrl": "https://s3.amazonaws.com/AKIAJC5RLADLUMVRPFDQ.book-thumb-images/adzic.jpg",
"title": "PyTest is a Fun."
}
return client.post('/api',
data=jsonify(payload), follow_redirects=True)
** Function to test: **
def test_api_post_book(client):
resp = api_post_book(client)
assert resp.status_code == 201
If I remove jsonify it returns another error as:
TypeError: 'NoneType' object is not subscriptable
This should work:
return client.post('/api', json=payload, follow_redirects=True)
Or if you absolutely want to use jsonify, use:
return client.post('/api', json=jsonify(payload).get_json(), follow_redirects=True)
You need to keep in mind that jsonify returns a Response object and not json.

Flask preventing PUT, DELETE, and POST

I am trying to test a Flask script I have written, by adding, amending, and deleting information. However, if I run anything other than methods=["GET"], I get an error saying that the method is not allowed.
The script I am running is:
#!flask/bin/python
from flask import Flask, jsonify, request, abort, make_response
from flask_cors import CORS
import csv
stocks = [
{"id": 1, "Stock": "BoI", "Price": 300},
{"id": 2, "Stock": "Apple", "Price": 499}
]
Next_ID = len(stocks)
app = Flask(__name__, static_url_path="", static_folder=".")
CORS(app, support_credentials=True)
#app.route("/")
#app.route("/Stocks")
def getAll():
return jsonify(stocks)
# curl http://127.0.0.1:5000
#app.route("/Stocks/<int:id>")
def getById(id):
sel_stock = list(filter(lambda s: s["id"] == id, stocks))
if len(sel_stock) == 0:
return jsonify ({}), 204
else:
return jsonify(sel_stock[0])
# curl http://127.0.0.1:5000/1
#app.route("/Stocks", methods=["POST"])
def create(id):
global Next_ID
if not request.json:
abort(400)
stock = {
"id": Next_ID,
"Stock": request.json["Stock"],
"Price": request.json["Price"],
}
Next_ID += 1
stocks.append(stock)
return jsonify(stock)
# return str(Next_ID)
#app.route("/Stocks", methods=["PUT"])
def update(id):
sel_stock = list(filter(lambda s: s["id"] == id, stocks))
if len(sel_stock) == 0:
abort(400)
sel_stock = sel_stock[0]
if not request.json:
abort(400)
reqJSON = request.json
if reqJSON["Stock"]:
sel_stock["Stock"] = reqJSON["Stock"]
if reqJSON["Price"]:
sel_stock["Price"] = reqJSON["Price"]
return jsonify(sel_stock)
#app.route("/Stocks", methods=["DELETE"])
def delete(id):
return "in delete"
if __name__ == "__main__":
app.run(debug = True)
If I run curl commands to get all the information or get the information by ID number, there is no issue. However, If I try the following curl command I get an error:
curl -i -H "Content-Type:application/json" -X POST -d "{\"Stock\":\"IBM\",\"Price\":\123}" http://127.0.0.1:5000/Stocks
TypeError: create() missing 1 required positional argument: 'id'
You do not need to pass id to your POST method since its url does not have id as parameter:
#app.route("/Stocks", methods=["POST"])
def create(): # removed id
"""some code here"""

Using Flask API, how to upload & download file from server using jwt_required decorator from browser/ client?

I suspect it has something got to do with refresh token. Could not understand how to use it by the docs. Can I know the exact code how to use it?
The access token is created during login:
#app.route('/login', methods=['POST','GET'])
def login():
username = request.form["email"]
password = request.form["password"]
my_token_expiry_time = datetime.timedelta(seconds=60)
segments = 0
access_token = None
if request.method == 'POST':
result_set = authenticate_user(username, password)
if result_set:
ss1 = select([nsettings]).\
where(nsettings.c.mattribute == 'my_jwt_expiry_time_min')
rss1 = g.conn.execute(ss1)
if rss1.rowcount > 0:
for r in rss1:
my_token_expiry_time = datetime.timedelta(seconds=
(int(r[nsettings.c.mvalue])* 60))
else:
my_token_expiry_time = datetime.timedelta(
seconds=(2 * 60 *60)) # 2 hours
#print result_set, 'result_set result_set'
session['email'] = result_set['email']
access_token = create_access_token(
identity=username, expires_delta=my_token_expiry_time)
user_dict = result_set
if user_dict:
session['email'] = user_dict['email']
session['id'] = result_set['id']
# users and related views
session['access_token'] = access_token
print access_token, 'aaaaaaaaaaa'
return jsonify({
'email': session['email'],
'user_id': result_set['id'],
'access_token': access_token,
'id': session['id'],
}), 200
else:
return jsonify({'message': "Invalid credentials, retry"}), 401
return "True"
The flask api call to upload:
#app.route('/rt/api/v1.0/issues/<int:issue_id>/documents', methods=['POST'])
#jwt_required
def rt_doc_upload(issue_id):
'''
Upload documents for a rt ticket.
'''
# Iterate through the list of files, we don't care about the
# attribute name. We consider only the first file and ignore the
# rest.
if 'id' in session:
uploader = "3"
minternal_only = True
bool_internal_update = False
msg_str = None
for attr, document in request.files.iteritems():
trans = g.conn.begin()
try:
orig_filename = document.filename
filename, upload_folder = check_or_insert_document(
orig_filename, uploader)
new_doc = add_doc(orig_filename, filename)
print orig_filename, 'origooooo'
ins = archival_docs.insert().values(new_doc)
rs = g.conn.execute(ins)
doc_id = rs.inserted_primary_key[0]
filename = (str(doc_id) + '_' + orig_filename)
stmt = archival_docs.update().values(stored_name=filename).\
where(archival_docs.c.id == doc_id)
g.conn.execute(stmt)
document.save(os.path.join(upload_folder, filename))
mattach_doc_id = genUrl(doc_id)
trans.commit()
return jsonify(
{'issue_doc_id': rs.inserted_primary_key[0]}), 201
except Exception, e:
print e
trans.rollback()
return jsonify({'message': "Did not find any file"}), 400
return jsonify({'message': "UNAUTHORIZED"}), 401
When used with runserver and on commenting the jwt_required decorator I am able to upload and download files
Using sqlalchemy core, python and flask. The api call to upload worked for more than a month, but suddenly stopped working now

How can I pass to graphql more than one record using Orientdb and Flask?

I has the following code, i try to build and microservice that allow me get specific fields in my application, am beginning with orientdb and graphql:
from flask import Flask, request
import graphene
import json
import pyorient
app = Flask(__name__)
class Person(graphene.ObjectType):
name = graphene.String()
middle_name = graphene.String()
last_name = graphene.String()
class Query(graphene.ObjectType):
person = graphene.Field(Person, id=graphene.Argument(graphene.Int))
persons = graphene.Field(Person)
def resolve_person(self, info, id):
with open('orientdb_config.json') as config_file:
orient_config = json.load(config_file)
try:
client = pyorient.OrientDB(orient_config["host"], orient_config["port"])
session_id = client.connect(orient_config["user"], orient_config["password"])
client.db_open(orient_config["database"], orient_config["user"], orient_config["password"])
if client is not None:
query = "SELECT * FROM Person WHERE #rid = #12: %(id)s" % {'id': id}
data = client.query(query)
print(data[0])
return data[0]
else:
return None
except Exception as e:
return None
def resolve_persons(self, info):
with open('orientdb_config.json') as config_file:
orient_config = json.load(config_file)
try:
client = pyorient.OrientDB(orient_config["host"], orient_config["port"])
session_id = client.connect(orient_config["user"], orient_config["password"])
client.db_open(orient_config["database"], orient_config["user"], orient_config["password"])
if client is not None:
query = "SELECT * FROM Person"
data = client.query(query)
result = []
for d in data:
result.append(d)
return result
else:
return None
except Exception as e:
return None
schema = graphene.Schema(query=Query)
#app.route("/", methods=['POST'])
def main():
data = json.loads(request.data)
return json.dumps(schema.execute(data['query']).data)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5002, debug=True)
Everything seems to work when I request a Person using its id, but when I try to obtain all the people, graphql responds with a null value, I verify the result of the query and the value is there.
In your GraphQL definition, you should have
persons = graphene.List(lambda: Person)

Categories

Resources