Python Flask - Passing hash input in API call - python

I am a beginner in making API. I have followed the blog https://blog.miguelgrinberg.com/post/designing-a-restful-api-with-python-and-flask and able to create the Get - Post API method.
I am using Flask to making Rest API. Please see the code below in which I want to take question as input in API and return an answer in JSON format by making my code as an API.
app = Flask(__name__)
#app.route('/match/api/v1', methods = ['POST'])
def my_form_post():
if not request.json or not 'question' in request.json:
abort(400)
input_text_p = request.json['question'] # access input from curl request
reference_data = request.json['data'] # to access data field from the API request
path = 'airtel_faq.xlsx'
question_list, answer_list = read_excel_file(path) # reading some reference data from an excel file
input_text = input_text_p.translate(None, string.punctuation) # remove punctuation
final_answer = find_similarity(input_text, answer_list, question_list)
print "Final Answer is : ", final_answer
values = [
{'id' : 1,
'answer' : final_answer # answer I want in JSON
'done' : False
}
]
return jsonify({'values': values}), 201
if __name__ == '__main__':
app.run(debug = True)
I am trying to pass hash input for data tag in the request to API. I am not aware how to do this. The curl request I am making is giving error:
Failed to decode JSON object: Expecting ',' delimiter or '}': line 1 column 80 (char 79)
The curl request I am making :
curl -i -H "Content-Type: application/json" -X POST -d '{"question":"Hi","cutoff":"0.3", "data":"{"q":"hello whats going on","a":"I am fine","type":"1"}"}' http://localhost:5000/match/api
Please let me know how to do this. Do I have to include anything in my script. Or is there a way to pass the JSON file in API call by giving path to the file.

In order to parse the JSON request, it needs to be valid JSON. Try this request:
curl -i -H "Content-Type: application/json" -X POST -d '{"question": "Hi", "cutoff": "0.3", "data": {"q": "hello whats going on", "a": "I am fine", "type": "1"}}' http://localhost:5000/match/api

Related

Read CSV file to Flask Restful API using cURL

I am trying to develop as a service where someone can send the csv file to my REST API which I dump in the database. My cURL request is reading the data but flask_restful is not able to process it. Can you please tell me what am I doing wrong and how can I fix it?
[EDITED BELOW]
I found after reading the docs that request.files lets you read the files from the POST request from a form. I also found a way to send a csv file through cURL as a form.
class ForBetaAndUpload(Resource):
def post(self, kind='quotes'):
# parser = reqparse.RequestParser()
file = request.files['file']
print(file)
# kind = parser.add_argument('kind').parse_args()['kind']
if kind:
if file and file[-3:]=='csv':
if kind == 'quotes':
try:
df = pd.read_csv(file)
df.to_sql('QUOTES', helper.conx, index=False, if_exists='append')
return jsonify({'message':'%s rows inserted in the databasee table successfully' %(df.shape[0])})
except Exception as e:
return jsonify({'exception': e})
if kind == 'trace':
try:
df = pd.read_csv(todos)
df.iloc[:10].to_sql('TRACE', helper.conx, index=False, if_exists='append')
return jsonify({'message':'%s rows inserted in the databasee table successfully' %(df.shape[0])})
except Exception as e:
return jsonify({'message': e})
else:
return jsonify({'message': 'Please provide a csv file'})
else:
return jsonify({'message':'Please provide the file for to update relevant table in the databse'})
api.add_resource(ForBetaAndUpload, '/upload', endpoint='upload')
if __name__ == "__main__":
app.run(debug=True)
cURL Request:
curl "https://localhost:5000/upload" -X POST -H 'Content-Type: txt/csv' -d trace.csv --insecure
I'm getting the following message:
curl: (35) error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown
protocol
API Error Message
code 400, message Bad HTTP/0.9 request type
('\x16\x03\x01\x02\x00\x01\x00\x01ü\x03\x03\x08Ú:ü^¢Ù~ö7W\x9fDyy\x16j\x7fõ>½\x82\x90uÎ&3ÿZ\x08êE\x00\x00')
How can I send a csv file to the flask restful_api. Is it right what I am doing or is there any other way to do it?
My solution to read csv from Flask is:
in Flask:
f = request.files['file']
f will be a handler to the file, you can then use csv_reader.
and to send the file:
curl -s "http://localhost:5000" \
-F file=#./myfile.csv \
-X POST \
-H 'enctype:multipart/form-data ; Content-Type:multipart/form-data'
And that should works. Let me know.

curl POST request

Hello we have problem to POST data using curl !!
curl "http://127.0.0.1:8000/construct" -X POST -H "Content-Type: application/json" -d '{"journal_id": "JE000001", "entry_date" : "2016-11-06", "create_time" : "2016-11-06 18:00:00", "created_by": "Adam", "post_status": "P", "account_code" : "100000", "amount" : 16453.24, "dr_cr" : "C"}'
Return 400
#app.route("/construct", methods = ['GET', 'POST'])
def construct():
if request.method == 'POST':
data = request.form['data']
data1 = loads(data)
conn, cursor = database_connect()
data1 = data_contruct_new(data1)
data1['pre_hash'] = get_pre_hash(cursor)
data1['nouce'] = call_nouce()
data1['hash'] = call_hash(data1)
conn.close()
return jsonpify(data1)
else:
return request.method # return method for test
Your service is expecting doubly-encoded data:
data = request.form['data']
data1 = loads(data)
Instead of just parsing the contents of the request as JSON, you're parsing the contents of the request as www-form-urlencoded, with a single field named data, and then parsing the contents of that form field as JSON.
The form field is the incoming contents parsed as a form. If you don't have one, don't use this.
If you want to parse the raw contents, that's either data or get_data:
data = request.data
… or:
data = request.get_data()
But if you've done everything properly on both sides, you don't even need this, just json or get_json:
data1 = request.get_json()
If you, for some reason, really do want doubly-encoded data, you need to generate that on the client side, and send the right Content-Type. That would look something like this mess:
'curl "http://127.0.0.1:8000/construct" -X POST -F 'data=%7B%22journal_id%22%3A%20%22JE000001%22%2C%20%22entry_date%22%20%3A%20%222016-11-06%22%2C%20%22create_time%22%20%3A%20%222016-11-06%2018%3A00%3A00%22%2C%20%22created_by%22%3A%20%22Adam%22%2C%20%22post_status%22%3A%20%22P%22%2C%20%22account_code%22%20%3A%20%22100000%22%2C%20%22amount%22%20%3A%2016453.24%2C%20%22dr_cr%22%20%3A%20%22C%22%7D'
Hopefully you can see that this is not what you actually want, unless the broken server side is completely out of your hands and can't be fixed.

Python requests module: Equivalent of cURL --data command

I'm trying to write a script that imitates a cURL command I make to change data on the target web page:
curl -u username:password "https://website.com/update/" --data "simChangesList=%5B%7B%22simId%22%3A760590802%2C%22changeType%22%3A2%2C%22targetValue%22%3A%220003077%22%2C%22effectiveDate%22%3Anull%7D%5D" --compressed
As you can see above, I am POSTing a url-encoded string to the target web page.
The following code does not work:
import requests
import urllib
enc = urllib.quote('[{"simId":760590802,"changeType":2,"targetValue":000307,"effectiveDate":null}]')
simChangesList = 'simChangesList=' + enc
print simChangesList
auth = s.post(url, data=simChangesList)
print auth.text
Even though I'm fairly certain the above code imitates my cURL command previously, but it obviously isn't.
I am getting a Required List parameter 'simChangesList' is not present error.
What is the equivalent of the cURL command to POST a url-encoded string with the requests module in Python?
EDIT:
I've tried to make multiple dictionaries with simChangesList as the key, but I cannot seem to do it.
Here are my attempts:
simChangesList: [{"simId":760590802,"changeType":2,"targetValue":000307,"effectiveDate":null}]
data = {'simChangesList': ['simId': 760590802, 'changeType': 2, 'targetValue': '0003077', 'effectiveDate': null]}
data['simChangesList'] = ['simId': 760590802, 'changeType': 2, 'targetValue': '0003077', 'effectiveDate': null]
simChangesList:[{"simId":760590802,"changeType":2,"targetValue":"000307","effectiveDate":null}]
payload = {
'simChangesList':
[{'simId': '760590802',
'changeType': '2',
'targetValue': '0003077',
'effectiveDate': 'null'}]
}

Flask Restful PUT update list with object

I want to use Flask Restful to update a list with an object using a PUT request.
The resulting JSON should look like:
{"EmployeeID":"12345", "firstname":"Joe","lastname":"Bloggs","SupervisorName":"Name","SupervisorID":"2468","role":"Role","active":"True","hours":["{'date':'01/01/2017','qty':'3','project':'Project 1'}"]"}
The Hours field in the JSON is a list. The aim is to append an object to the list on each PUT request.
The Parser for hours is:
parser.add_argument('hours', action='append')
The Put method code is:
def put(self, EmployeeID=None):
data = parser.parse_args()
if not data:
data = {'ERROR': 'No Data'}
return jsonify(data)
else:
if EmployeeID:
if mongo.db.employee.find_one({'EmployeeID': EmployeeID}):
mongo.db.employee.update_one({'EmployeeID': EmployeeID}, {set: {"hours": data.get('hours')}})
return {'response': 'Employee:'+str(EmployeeID)+' updated'}
else:
return {'Error': 'employee ' + str(EmployeeID) + ' not found'}
else:
return {'response': 'Employee ID missing'}
Is the update_one method the right one to use here?
using curl PUT request :
curl -H "Content-type: application/json" -X PUT -d '{"EmployeeID":"1234",...,"hours":{'time':'','qty':'3','project':'Project 1'}}' http://127.0.0.1:5000/api/people/1234
Gave the error:
{
"message": "Failed to decode JSON object: Expecting property name enclosed in double quotes: line 1 column 168 (char 167)"
}
But When I add the quotations into the request it return an error:
{
"message": "Failed to decode JSON object: Unterminated string starting at: line 1 column 167 (char 166)"
}
I can't figure out whether there is an issue with the requests or with the actual Flask-Restful code.
What is the correct way to go about updating a Mongo document list with an object?
I don't have much experience with Flask, but from the error messages you've posted, it looks like the JSON in the request cannot be correctly decoded by Flask. I believe this is because you are using single quotes in your JSON string and are wrapping the entire JSON with yet another set of single quotes.
Try to just use double quotes in your JSON string and wrap the entire JSON string in single quotes like so:
curl -H "Content-type: application/json" -X PUT -d '{"EmployeeID":"1234","hours":{"time":"","qty":"3","project":"Project 1"}}' http://127.0.0.1:5000/api/people/1234
I think that should solve the issue of not being able to decode JSON form the request.
If anyone runs into this issue I finally got there.
I had to change the RequestParser:
parser.add_argument('hours')
Removing the action='append'
Then using the mongo update:
mongo.db.employee.update_one({'EmployeeID': EmployeeID}, {'$addToSet': {"hours": data.get('hours')}})

Problems with python + json vs. curl

so when I run the python code the server (google) give me a different response than when I run curl command. Can someone tell me where I'm wrong please?
code:
import urllib2, simplejson
def MapsWIFI(card):
req = urllib2.Request("https://www.googleapis.com/geolocation/v1/geolocate?key=AI...")
jWifi = """
{
"wifiAccessPoints": [
{
"macAddress": "64:D1:A3:0A:11:65",
"channel": 6,
},
... #some AP here
]
}
"""
print jWifi
req.add_header("Content-Type", "application/json")
jWifiReport = urllib2.urlopen(req,simplejson.dumps(jWifi)).read()
print jWifiReport
APdetected = str(len(wifiCell))
mapsDict = simplejson.loads(jWifiReport)
location = str(mapsDict.get("location",{}))[1:-1]
accuracy = "Accuracy: "+str(mapsDict.get("accuracy",{}))[1:-1]
mapMe = "|---"+location.split(",")[0]+"\n|---"+location.split(",")[1][1:]+"\n|---$
return mapMe
MapsWIFI("wlp8s0")
And the command is:
curl -d #file2.json -H "Content-Type: application/json" -i "https://www.googleapis.com/geolocation/v1/geolocate?key=AI..."
where file2.json contains exactly jWifi in that format.
The problem is that, as said, the location returned by the code is different from the location returned by curl. I don't get error code so I thing that the syntax is correct.
The data is already a JSON encoded string, you don't want to encode it twice.
Pass it in without encoding it again:
jWifiReport = urllib2.urlopen(req, jWifi).read()
You only need to encode if you have a Python data structure (a dictionary in this case).

Categories

Resources