HTTP 400 Bad Request on Flask app with cUrl - python

I am attempting to do a basic request on my Flask-app with cUrl.
This is my Flask code:
#application.route('/fb_checkin/', methods=['POST'])
def checkin():
qr_code = request.form['qr']
provider_name = request.form['provider']
#Lookup Access Key by qr in database
resp = requests.post("https://<USERNAME>:<PASSWORD>#<DOMAIN>.cloudant.com/socialmattic_users/_find",
'{"selector": {"qr": "' + qr_code + '"}}')
token = resp.json()['fb_access_token']
This is my curl command:
curl -X POST 'localhost:5000/fb_checkin/?qr=default&provider=void'
After issuing the curl command an HTTP 400 error is returned.
Is anyone able to tell me why this is the case?
Thanks for any help.

curl should be and also no quotes to URL
curl --data "qr=default&provider=void" http://localhost:5000/fb_checkin/

Related

API authentication with python request

I am testing some APIs whose only documentation is the response to the requests for the respective APIs. Basically when I execute I get for all the requests: {"detail":"Authentication credentials were not provided."} except for the login request which is successful, this is because I obviously pass the parameters to it as required I guess.
Below is my code for the requests:
import requests
credential = {'identity' : 'xxxxxxx', 'password': 'xxxxxx'}
#use the 'auth' parameter to send requests with HTTP Basic Auth: auth = ('xxxxxx', 'xxxxxxx')
#url list
api_login = 'https://xxxxxxxx/api/login'
api_channel = 'https://xxxxxxxx/api/channel'
#requests
r_login = requests.post(url=api_login, data = credential)
print(r_login.status_code)
r_channels = requests.get(url=api_channel)
print(r_channels.text)
If it can help, following the info for the API that fail the authentication:
Curl
curl -X 'GET' \
'https://xxxxxxx/api/channels' \
-H 'accept: application/json' \
-H 'X-CSRFToken: xxxxxxxxx'
Request URL
https://xxxxxxx/api/channels
At the moment I've tried using basic authentication in the GET request and passing the headers in the documentation curl but as I'm not a bit practical I might have got it wrong.

Flask not receiving arguments from curl post

Trying to implement a flask API with the following code:
import tweepy,flask,os,flask_api,re,json,logging
app = flask.Flask(__name__,template_folder='')
#app.route('/',methods=['POST'])
def answer():
app.logger.info('server responding')
for key,value in flask.request.args.items():
app.logger.info(key+':'+value)
return 'Server on line'
#app.route('/',methods=['GET'])
def home():
return flask.render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)#use_reloader=False
logging.basicConfig(filename='error.log',level=logging.DEBUG)
app.logger.info('Successfull info message')
app.logger.error('Successfull error message')
When I try to curl it wit windows,
curl -X POST -d query=cheese http://127.0.0.1:5000/
(long form)
curl --header "Content-Type: application/json" --request POST --data '{"query":"cheese"}' http://127.0.0.1:5000/
I get
INFO in logtest: server responding
But not a single key/value pair is returned
flask.request.args are URL query parameters.
curl --data is body.
You're sending a request body but expecting them to show up in the URL params. Which will obviously not work.
You need to access request.data instead. There is a convenience method get_json() that you can use to have Flask parse the body into a dictionary for you.

Django Can't load Json in POST request body if more than 1 parameter is passed in URL

I have a views.py with an endpoint like this:
def endpoint(request):
if request.method == "POST":
body = request.body.decode('utf-8')
body = json.loads(body)
param1 = request.GET.get('param1','default1')
param2 = request.GET.get('param2','default2')
My urls.py have this urlpattern:
url(r'^endpoint$', views.endpoint, name="endpoint")
The problem I have is that if I send requests in one of the following ways it works fine:
curl -X POST http://localhost:8000/endpoint -d #data.json
curl -X POST http://localhost:8000/endpoint?param1=val1 -d #data.json
curl -X POST http://localhost:8000/endpoint?param2=val2 -d #data.json
But if I send a request with both parameters:
curl -X POST http://localhost:8000/endpoint?param1=val1&param2=val2 -d #data.json
I get the exception:
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char
0)
Why I get JSONDecodeError when having multiple parameters? Is it because it's a POST request?
EDIT: I have to use a file data.json because de body of the request is quite big.
I also tried with a smaller json
curl -X POST http://localhost:8000/endpoint?param1=val1&param2=val2 -d "{"a": "b"}"
To debug I inserted this on the beginning of the code:
print("request body:")
print(request.body)
I get this in the terminal:
request body:
b''
It seems Django don't even receive the request body
in the command line the & means run command in background, try to put url in the double quotes: "http://localhost:8000/endpoint?param1=val1&param2=val2"
curl -X POST "http://localhost:8000/endpoint?param1=val1&param2=val2" -d #data.json

Flask API failing to decode JSON data. Error: "message": "Failed to decode JSON object: Expecting value: line 1 column 1 (char 0)"

I'm setting up a simple rest api using flask and flask-restful. Right now all I'm trying to do is create a post request with some Json data, and then return it just to see if it works. I always get the same error "message": "Failed to decode JSON object: Expecting value: line 1 column 1 (char 0)"
Below is my code
from flask import Flask, jsonify, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class Tester(Resource):
def get(self):
return {'about': 'Hello World'}
def post(self):
data_json = request.get_json(force=True)
return {'you sent': data_json}
api.add_resource(Tester, '/')
if __name__ == '__main__':
app.run(debug=True)
The curl request I am making to test this is below, I've also tried making request using postman
curl -H "Content-Type: application/json" -X POST -d '{'username':"abc",'password':"abc"}' http://localhost:5000
You need to select raw -> JSON (application/json) in Postman like this:
When it comes to your cURL request, answer explains that windows's command line lacks support of strings with single quotes, so use:
curl -i -H "Content-Type: application/json" -X POST -d "{\"username\":\"abc\", \"password\":\"abc\"}" 127.0.0.1:5000
instead:
curl -H "Content-Type: application/json" -X POST -d '{'username':"abc",'password':"abc"}' http://localhost:5000
\ escapes " character.
You also need to have the Content-Length header enabled.
Some additional information in case you are using python script to test your flask api like me - you have to dumps before adding the dictionary to the data field.
import requests
import json
response = requests.post(
'http://localhost:5000',
data = json.dumps({'username':"abc",'password':"abc"}),
headers = {"Content-Type": "application/json"}
)
The curl request (payload) is incorrect. Use double quotes in the payload.
curl -H "Content-Type: application/json" -X POST -d '{"username":"abc","password":"abc"}' http://localhost:5000

How to send data on a curl redirect?

I have an API which is currently on HTTP, I moved the API using SSLify library in python flask.
Now when I send data using curl request
curl -v -k -H "Content-Type: application/json" -X POST \
--data '{"title":"foobar","body": "This body"}' \
-L http://X.Y.Z.W.us-west-2.compute.amazonaws.com/test
It returns an empty string to me by using request.data
If I make the request to begin with https it returns correct value. If there is a redirect how can I send data ?
SSLify issues a 301 or 302 redirect status code depending on your configuration. So you need to pass --post301 or --post302 to curl.
The reason for this can be found in the curl man page:
When curl follows a redirect and the request is not a plain GET (for
example POST or PUT), it will do the following request with a GET
if the HTTP response was 301, 302, or 303. If the response code was
any other 3xx code, curl will re-send the following request using
the same unmodified method.
You can tell curl to not change the non-GET request method to GET
after a 30x response by using the dedicated options for that: --post301, --post302 and -post303.

Categories

Resources