I can't communicate with SQL - python

I try to connect to MySQL, it doesn't show the success status of user added, i get the following error :
{"message": "The method is not allowed for the requested URL."}
I don't understand what "method" it is talking about...the POST i am doing with POSTMAN ? some help would be greatly appreciated !
So i change my code to put the MySQL() in the POST method, i still get the same error....
Here is my "api.py" code :
from flask import Flask
from flask_restful import Resource, Api, reqparse
from flaskext.mysql import MySQL
app = Flask(__name__)
api = Api(app)
class CreateUser(Resource):
def post(self):
try:
# Parse the arguments
parser = reqparse.RequestParser()
parser.add_argument('email', type=str, help='Email address to create user')
parser.add_argument('password', type=str, help='Password to create user')
args = parser.parse_args()
_userEmail = args['email']
_userPassword = args['password']
return {'Email': args['email'], 'Password': args['password']}
mysql = MySQL()
# MySQL configurations
app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_DB'] = 'itemlistdb'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
mysql.init_app(app)
conn = mysql.connect()
cursor = conn.cursor()
cursor.callproc('spCreateUser',(_userEmail,_userPassword))
data = cursor.fetchall()
if len(data) is 0:
conn.commit()
return {'StatusCode':'200','Message': 'User creation success'}
else:
return {'StatusCode':'1000','Message': str(data[0])}
except Exception as e:
return {'error': str(e)}
api.add_resource(CreateUser, '/CreateUser')
if __name__ == '__main__':
app.run(debug=True)
i use a stored procedure to write the values in db, the procedure is spCreateUser, here is the code of it :
BEGIN
if ( select exists (select 1 from tblUser where UserName = p_username) )
THEN
select 'Username Exists !!';
ELSE
insert into tblUser(
UserName,
Password
)
values
(
p_Username,
p_Password
);
END IF;
END

If a resource is invoked with an unsupported HTTP method, the API will return a response with status 405 Method Not Allowed.
I am guessing your trying to view your resource on browser so you having this error. If you want to see resource on browser it must support http get method.
class CreateUser(Resource):
def post(self):
cur.execute("INSERT INTO table VALUES(?,?)",(email,password))
def get(self):
#...
And one more thing QueryDb method would not called by self you have to call it in one of http methods.

Ok i solved everything...Might be useful for others :
So first i put the name of the function with a "post" not a "Post".
Then i was getting the following message :
"A setup function was called after the first request was handled"
The solution to get rid of that is to disable debug mode....
so here is the code working :
from flask import Flask
from flask_restful import Resource, Api, reqparse
from flaskext.mysql import MySQL
app = Flask(__name__)
api = Api(app)
class CreateUser(Resource):
def post(self):
try:
# Parse the arguments
parser = reqparse.RequestParser()
parser.add_argument('email', type=str, help='Email address to create user')
parser.add_argument('password', type=str, help='Password to create user')
args = parser.parse_args()
_userEmail = args['email']
_userPassword = args['password']
#return {'Email': args['email'], 'Password': args['password']}
mysql = MySQL()
# MySQL configurations
app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_DB'] = 'itemlistdb'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
mysql.init_app(app)
conn = mysql.connect()
cursor = conn.cursor()
cursor.callproc('spCreateUser',(_userEmail,_userPassword))
data = cursor.fetchall()
if len(data) is 0:
conn.commit()
return {'StatusCode':'200','Message': 'User creation success'}
cursor.close()
conn.close()
else:
return {'StatusCode':'1000','Message': str(data[0])}
cursor.close()
conn.close()
except Exception as e:
return {'error': str(e)}
api.add_resource(CreateUser, '/CreateUser')
if __name__ == '__main__':
app.run(debug=False)

Related

creating a webservice in flask that queries a Mysql database and returns json

Please help:
I am trying to create a webservice in flask (this is my first time) that takes a str, queries an external mysql database and returns 1 row as json.
I am sure there are other of issues with the code below (all suggestions much appreciated), but I cannot even see them yet, because when I try to access example.com/webservice/vin/ I get "Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application." from nginx.
PLease can someone guide me where I am going wrong?
example.com return Hello from app_name running in docker...yayy. Its the other route that isnt working.
from flask.ext.mysqldb import MySQL
import json
app.config['MYSQL_HOST'] = 'xxx'
app.config['MYSQL_USER'] = 'xxx'
app.config['MYSQL_PASSWORD'] = 'xxx'
app.config['MYSQL_DB'] = 'xxx'
mysql = MySQL(app)
#app.route("/")
def index():
# Use os.getenv("key") to get environment variables
app_name = os.getenv("APP_NAME")
if app_name:
return f"Hello from {app_name} running in a Docker container behind Nginx!"
return "Hello from Flask"
#app.route('/webservice/vin/<vin>', methods=['GET'])
def get_vehicle(vin):
sql = "SELECT * FROM `table` where column = '(%s )';" %(vin)
cur = mysql.connection.cursor()
cur.execute(sql)
row_headers=[x[0] for x in cur.description] #this will extract row headers
rv = cur.fetchall()
json_data=[]
for result in rv:
json_data.append(dict(zip(row_headers,result)))
return json.dumps(json_data)
from flask import make_response
#app.errorhandler(404)
def not_found(error):
return make_response(jsonify({'error': 'Not found'}), 404)

Flask API facing InterfaceError with PostgreSQL

I have a Flask API based on Flask RestPlus extension and is hosted on Google App Engine. The API does a basic job of fetching data from a Google Cloud SQL PostgreSQL. The API is working fine otherwise but sometimes it starts returning InterfaceError: cursor already closed.
Strangely, when I do a gcloud app deploy, the API starts working fine again.
Here's a basic format of the API:
import simplejson as json
import psycopg2
from flask import Flask, jsonify
from flask_restplus import Api, Resource, fields
from psycopg2.extras import RealDictCursor
app = Flask(__name__)
app.config['SWAGGER_UI_JSONEDITOR'] = True
api = Api(app=app,
doc='/docs',
version="1.0",
title="Title",
description="description")
app.config['SWAGGER_UI_JSONEDITOR'] = True
ns_pricing = api.namespace('cropPricing')
db_user = "xxxx"
db_pass = "xxxx"
db_name = "xxxxx"
cloud_sql_connection_name = "xxxxxx"
conn = psycopg2.connect(user=db_user,
password=db_pass,
host='xxxxx',
dbname=db_name)
#ns_pricing.route('/list')
class States(Resource):
def get(self):
"""
list all the states for which data is available
"""
cur = conn.cursor(cursor_factory=RealDictCursor)
query = """
SELECT
DISTINCT state
FROM
db.table
"""
conn.commit()
cur.execute(query)
states = json.loads(json.dumps(cur.fetchall()))
if len(states) == 0:
return jsonify(data=[],
status="Error",
message="Requested data not found")
else:
return jsonify(status="Success",
message="Successfully retreived states",
data=states)
What should I fix to not see the error anymore?
It would be good to use the ORMs such as SQLAlchemy / Flask-SQLAlchemy which would handle the establishing / re-establishing the connection part.
Though, if using psycopg2. you can use try except to catch the exception and re-establish the connection again.
try:
cur.execute(query)
except psycopg2.InterfaceError as err:
print err.message
conn = psycopg2.connect(....)
cur = conn.cursor()
cur.execute(query)

Flask mysql getting response to SQL commands (not using SQL-Alchemy)

First, I understand the value of using ORM solutions, and will use SQL-Alchemy later.
I have installed Flask and am using flask-mysql.
I do not know how to get the results for a SQL "desc " command.
Here is the code I'm working with:
from flask import Flask, render_template, request, redirect, jsonify
import requests
from flaskext.mysql import MySQL
app = Flask(__name__)
#app.route("/")
def main():
return render_template('login.html')
#app.route("/login", methods=['POST'])
def login():
#username = request.form['username'] #not using the form fields yet
#password = request.form['password']
mysql = MySQL()
app.config['MYSQL_DATABASE_USER'] = '<my user here>'
app.config['MYSQL_DATABASE_PASSWORD'] = '<password here>'
app.config['MYSQL_DATABASE_DB'] = '<database name here>'
app.config['MYSQL_DATABASE_HOST'] = '<database server IP address here>'
mysql.init_app(app)
conn = mysql.connect()
cursor = conn.cursor()
#cursor = mysql.connection.cursor() #invalid code, at least for this version of flask-mysql
cursor.execute("desc user;")
result = jsonify(cursor.fetchall())
#row = cursor.fetchone()
return "<!DOCTYPE html><html><body>" + str(result)+ "</body></html>"
if __name__ == "__main__":
app.run()
It appears to be connecting to the database, logging in, and sending the desc command OK because result's contents are "Response 268 bytes [200 OK]" (can see that by looking at the page source code after getting the response in the browser).
Is there any way to get the results (table description) and not just an "OK I ran this command"?
Thank you.
I suppose you would like to get all records and sort them in desc order. You may try this.
from flask_mysqldb import MySQL
app.config['MYSQL_HOST'] = 'localhost'
app.config['MYSQL_USER'] = 'root'
app.config['MYSQL_PASSWORD'] =
app.config['MYSQL_DB'] =
app.config['MYSQL_CURSORCLASS'] = 'DictCursor'
# initialize mysql
mysql = MySQL(app)
...
#app.route('/posts')
def posts():
cur = mysql.connection.cursor()
result = cur.execute('SELECT * FROM posts ORDER BY postdate DESC ')
posts = cur.fetchall()
if result > 0:
return render_template('posts.html', posts=posts)
else:
message = 'I shouldn't find any post'
return render_template('posts.html', message=message)
cur.close

Flask RESTful API: Issue with db connection pool

I'm trying to create REST API endpoints using flask framework. This is my fully working script:
from flask import Flask, jsonify
from flask_restful import Resource, Api
from flask_restful import reqparse
from sqlalchemy import create_engine
from flask.ext.httpauth import HTTPBasicAuth
from flask.ext.cors import CORS
conn_string = "mssql+pyodbc://x:x#x:1433/x?driver=SQL Server"
auth = HTTPBasicAuth()
#auth.get_password
def get_password(username):
if username == 'x':
return 'x'
return None
app = Flask(__name__)
cors = CORS(app)
api = Api(app)
class Report(Resource):
decorators = [auth.login_required]
def get(self):
parser = reqparse.RequestParser()
parser.add_argument('start', type = str)
parser.add_argument('end', type = str)
args = parser.parse_args()
e = create_engine(conn_string)
conn = e.connect()
stat = """
select x from report
"""
query = conn.execute(stat)
json_dict = []
for i in query.cursor.fetchall():
res = {'x': i[0], 'xx': i[1]}
json_dict.append(res)
conn.close()
e.dispose()
return jsonify(results=json_dict)
api.add_resource(Report, '/report')
if __name__ == '__main__':
app.run(host='0.0.0.0')
The issue is that I get results when I call this API only for a day or so after which I stop getting results unless I restart my script (or sometimes even my VM) after which I get results again. I reckon there is some issue with the database connection pool or something but I'm closing the connection and disposing it as well. I have no idea why the API gives me results only for some time being because of which I have to restart my VM every single day. Any ideas?
Per my experience, the issue was caused by coding create_engine(conn_string) to create db pool inside the Class Report so that always do the create & destory operations of db pool for per restful request. It's not correct way for using SQLAlchemy ORM, and be cause IO resouce clash related to DB connection, see the engine.dispose() function description below at http://docs.sqlalchemy.org/en/rel_1_0/core/connections.html#sqlalchemy.engine.Engine:
To resolve the issue, you just need to move e = create_engine(conn_string) to the below of the code conn_string = "mssql+pyodbc://x:x#x:1433/x?driver=SQL Server" and remove the code e.dispose() both in the Class Report, see below.
conn_string = "mssql+pyodbc://x:x#x:1433/x?driver=SQL Server"
e = create_engine(conn_string) # To here
In the def get(delf) function:
args = parser.parse_args()
# Move: e = create_engine(conn_string)
conn = e.connect()
and
conn.close()
# Remove: e.dispose()
return jsonify(results=json_dict)

flask-restful: how to parse parameters when connected to sql server db?

I want to create a REST API using python flask. So anytime I do this:
localhost/customers?cust_country=USA
I want to fetch every row from table 'customers' where everyone is from USA.
This is the script I've so far:
from flask import Flask, request
from flask_restful import Resource, Api
from sqlalchemy import create_engine
from flask_restful import reqparse
e = create_engine("mssql+pyodbc://....")
app = Flask(__name__)
api = Api(app)
parser = reqparse.RequestParser()
parser.add_argument('cust_country', type = 'string')
class Dep(Resource):
def get(self):
conn = e.connect()
args = parser.parse_args()
query = conn.execute("select * from customers where cust_country = ?", [args['cust_country']])
print(query)
return {'custid': [i[0] for i in query.cursor.fetchall()]}
api.add_resource(Dep, '/customers')
if __name__ == '__main__':
app.run()
I'm getting this error:
C:\Users\x>curl 127.0.0.1:5000/customers?cust_country=USA 404 Not
Found Not Found The requested URL was not found on
the server. If you entered the URL manually please check your
spelling and try again.
======================
part 2: sending multiple parameters:
from flask import Flask
from flask_restful import Resource, Api
from flask_restful import reqparse
from sqlalchemy import create_engine
e = create_engine("x")
parser = reqparse.RequestParser()
parser.add_argument('cust_country', type = str)
parser.add_argument('cust_name', type = str)
app = Flask(__name__)
api = Api(app)
class Dep(Resource):
def get(self):
args = parser.parse_args()
conn = e.connect()
query = conn.execute("select cust_id from customers where cust_country = ? and cust_name = ?", [args['cust_country'], args['cust_name']])
return {'custid': [i[0] for i in query.cursor.fetchall()]}
api.add_resource(Dep, '/customers')
if __name__ == '__main__':
app.run()
this is what I'm using in my curl:
curl "127.0.0.1:5000/customers?cust_country=USA&cust_name=Wascals"
One error that you may be facing is by using
parser.add_argument('cust_country', type = 'string') which is wrong.
It should be parser.add_argument('cust_country', type = str).
Also I would suggest to use app.run(debug=True) as it will help you debug simple errors.

Categories

Resources