Amazon Seller Central - SP-API - Create a feed document - InvalidInput - python

Trying to create feed document (here ) and I'm getting InvalidInput error code.
Authentication works well (I tried other endpoints and it works) so I think headers are not the issue.
Here is my sample code:
endpoint = 'https://sellingpartnerapi-eu.amazon.com/feeds/2020-09-04/documents'
body = {
"contentType": "text/tab-separated-values; charset=UTF-8"
}
resp = requests.post(
endpoint,
auth=self.amazon_auth.auth,
headers=self.amazon_auth.headers,
json=body
)
return resp
Response code:
{'errors': [{'code': 'InvalidInput',
'message': 'Invalid Input',
'details': ''}]}
I was also trying to use different contentType and charset (like text/plain) but I receive same error code!
This is first step of Submit feed tutorial.
I'm trying to create feed so I can get cartonIds to download labels for a shipment I created over Amazon Seller Central.
Any hint, help is more than welcome!
Thanks!

I solved this issue by:
requests.post(data=json.dumps(body))
Also make sure you pass the body for signing as well

I use RestSharp
restRequest1.AddParameter(....); gave me the same error as yours Invalid Input
but the below line gave me a response value
restRequest1.AddJsonBody(new { contentType = "text/xml; charset=UTF-8" });
It serializes obj to json format and adds it to the request body.

This code snippet in C# worked for me, i successfully uploaded a feed
My upload method:
private static bool UploadFile(byte[] encrypted, string url)
{
bool isUploaded = false;
var contentType = "text/tab-separated-values; charset=UTF-8";
var parameter = new Parameter
{
Name = contentType,
Value = encrypted,
Type = ParameterType.RequestBody
};
var restRequest = new RestRequest(Method.PUT);
restRequest.Parameters.Add(parameter);
var restClient = new RestClient(url);
var response = restClient.Execute(restRequest);
isUploaded = response.StatusCode == System.Net.HttpStatusCode.OK;
return isUploaded;
}

Related

I don't know the cause and solution of keyerror

I'm a beginner.
What I used was flask and pymongo.
If you press the button, it's "Like". It should be +1, but there is a key error at the bottom.
My python route code:
#app.route('/api/like', methods=['POST'])
def like_movie():
title_receive = request.form['title_give']
movie = db.toytoy.find_one({'title': title_receive})
current_like = movie['like']
new_like = current_like + 1
db.toytoy.update_one({'title': title_receive}, {'$set': {'like': new_like}})
return jsonify({'msg': 'like!'})
This is how I POST from JS
function like_movie(title) {
$.ajax({
type: 'POST',
url: '/api/like',
data: {title_give: title},
success: function (response) {
console.log(response)
alert(response['msg']);
window.location.reload();
}
});
}
I get an exception as below:
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'title_give'
What I want is if it's 'like_btn'. If you press the button, it becomes +1.
The base problem in what you did is not respecting Content-type. From front JS, you are making a POST with JSON object. Which makes the request to have a content type of application/json.
In backend code, you use request.form which expects the request to be in the form encoded types (like application/x-www-form-urlencoded, multipart/form-data) etc.
So, you need to read the JSON content in backend, instead of reading from a form which is not available. Like below:
ui_req = request.get_json()
title_receive = ui_req['title_give']
And then parse other structures accordingly.

Flask displaying response in cmd but not in view

I am reviewing this repository https://github.com/ibrahim4529/flask-chatbot to get an inspiration and see how a model can be deployed in a chat UI. I am able to do this in Flask but ran across a quirky situation that I am not sure how to resolve. The UI accepts the first initial message that I type, but when I try returning the response, I get an 'undefined' appended to every line that is supposed to be the bot's response. On CMD though, my function is returning response. I've provided screenshots below:
Here is my routing:
#app.route('/')
def hello():
return render_template('index.html')
#app.route('/ask', methods={'POST', 'GET'})
def ask():
if request.method == 'POST':
message = (request.form['messageText'])
bresponse = response(message)
return render_template('Index.html', bresponse=bresponse)
'response' is a function that spits out the response of the model (this is the 'Rrraawwwwg!' response from the input).
Below is the js that I reviewed from the link that I am using:
$('#chatbot-form').submit(function(e) {
e.preventDefault();
var message = $('#messageText').val();
$(".media-list").append('<li class="media"><div class="media-body"><div class="media"><div style = "text-align:right; color : #2EFE2E" class="media-body">' + message + '<hr/></div></div></div></li>');
$.ajax({
type: "POST",
url: "/ask",
data: $(this).serialize(),
success: function(response) {
//console.log(response);
$('#messageText').val('');
var answers = response.answers;
const chatPanel = document.getElementById("chatPanel");
$(".media-list").append('<li class="media"><div class="media-body"><div class="media"><div style = "color : white" class="media-body">' + answers + '<hr/></div></div></div></li>');
$(".fixed-panel").stop().animate({ scrollTop: $(".fixed-panel")[0].scrollHeight}, 1000);
I am not sure what I am missing. I am seeing the response in the cli, but seeing an undefined in the UI.
Thanks in advance!
I finally was able to make this work. I've updated ajax to below:
var answers = response;
$('#messageText').val();
I was also printing the response function, instead of returning it; reason I am seeing the response in the console and not in the view. This was the main culprit.

Python request.post Missing Required Param

I've been looking around and trying to get a post request to work, but I haven't found any luck. I keep getting a MISSING_REQUIRED_PARAM each time the request is being made. My following code is shown below.
def create_sign_group(group_name, header, url):
temp_header = header
temp_header['Content-Type'] = 'application/json'
temp_header['Accept'] = 'application/json'
data = {
"GroupCreationInfo": {
"groupName": group_name
}
}
res = requests.post(url + 'groups', headers=temp_header, data=json.dumps(data))
if res.status_code == 200:
print('{} Group Created...'.format(group_name))
else:
print(res.status_code)
print(res.headers)
print(res.text)
exit(res.status_code)
I've tried using json instead of data, but still getting the same error. Using a the REST API client I was able to successfully make the call. The rest client is shown below:
If anyone can point shine some knowledge and point me in the right direction I would greatly appreciate it. Take care.
You should assign headers=temp_header not headers=header. MISSING_REQUIRED_PARAM is often griping about the content type header, which, as you can see IS being included in your screenshot test.
So I figured it out, I guess I was passing the wrong payload into the data param. I changed the code to:
data = {
"groupName": group_name
}
It looks like I didn't need the "GroupCreationInfo" parameter.

Accept Post request to nodejs from django

I am making a post request from django to nodejs
v = {}
v['id'] = 'test'
y=requests.post('http://localhost:3000',params=v)
How can I parse this data in nodejs? Below is my code, but it shows undefined.
app.post('/', function (req, res) {
console.log(req.body.id) //this shows Cannot read property 'id' of undefined
res.send('hello')
})
note that with python-requets the POST verb expects a dictionary as data
v = {}
v['id'] = 'test'
y=requests.post('http://localhost:3000',data=v)
params is generally used by the get verb. Having said that I am not sure why you want to connect django and node in this way. Wouldn't it be easier to write the entire thing in one or the other?
Have you enabled the body parser?
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies

Google+ login - Server side flow - Python - Google App Engine

I am building an app on Google App Engine using Flask. I am implementing Google+ login from the server-side flow described in https://developers.google.com/+/web/signin/server-side-flow. Before switching to App Engine, I had a very similar flow working. Perhaps I have introduced an error since then. Or maybe it is an issue with my implementation in App Engine.
I believe the url redirected to by the Google login flow should have a GET argument set "gplus_id", however, I am not receiving this parameter.
I have a login button created by:
(function() {
var po = document.createElement('script');
po.type = 'text/javascript'; po.async = true;
po.src = 'https://plus.google.com/js/client:plusone.js?onload=render';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(po, s);
})();
function render() {
gapi.signin.render('gplusBtn', {
'callback': 'onSignInCallback',
'clientid': '{{ CLIENT_ID }}',
'cookiepolicy': 'single_host_origin',
'requestvisibleactions': 'http://schemas.google.com/AddActivity',
'scope': 'https://www.googleapis.com/auth/plus.login',
'accesstype': 'offline',
'width': 'iconOnly'
});
}
In the javascript code for the page I have a function to initiate the flow:
var helper = (function() {
var authResult = undefined;
return {
onSignInCallback: function(authResult) {
if (authResult['access_token']) {
// The user is signed in
this.authResult = authResult;
helper.connectServer();
} else if (authResult['error']) {
// There was an error, which means the user is not signed in.
// As an example, you can troubleshoot by writing to the console:
console.log('GPlus: There was an error: ' + authResult['error']);
}
console.log('authResult', authResult);
},
connectServer: function() {
$.ajax({
type: 'POST',
url: window.location.protocol + '//' + window.location.host + '/connect?state={{ STATE }}',
contentType: 'application/octet-stream; charset=utf-8',
success: function(result) {
// After we load the Google+ API, send login data.
gapi.client.load('plus','v1',helper.otherLogin);
},
processData: false,
data: this.authResult.code,
error: function(e) {
console.log("connectServer: error: ", e);
}
});
}
}
})();
/**
* Calls the helper method that handles the authentication flow.
*
* #param {Object} authResult An Object which contains the access token and
* other authentication information.
*/
function onSignInCallback(authResult) {
helper.onSignInCallback(authResult);
}
This initiates the flow at "/connect" (See step 8. referenced in the above doc):
#app.route('/connect', methods=['GET', 'POST'])
def connect():
# Ensure that this is no request forgery going on, and that the user
# sending us this connect request is the user that was supposed to.
if request.args.get('state', '') != session.get('state', ''):
response = make_response(json.dumps('Invalid state parameter.'), 401)
response.headers['Content-Type'] = 'application/json'
return response
# Normally the state would be a one-time use token, however in our
# simple case, we want a user to be able to connect and disconnect
# without reloading the page. Thus, for demonstration, we don't
# implement this best practice.
session.pop('state')
gplus_id = request.args.get('gplus_id')
code = request.data
try:
# Upgrade the authorization code into a credentials object
oauth_flow = client.flow_from_clientsecrets('client_secrets.json', scope='')
oauth_flow.redirect_uri = 'postmessage'
credentials = oauth_flow.step2_exchange(code)
except client.FlowExchangeError:
app.logger.debug("connect: Failed to upgrade the authorization code")
response = make_response(
json.dumps('Failed to upgrade the authorization code.'), 401)
response.headers['Content-Type'] = 'application/json'
return response
# Check that the access token is valid.
access_token = credentials.access_token
url = ('https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=%s'
% access_token)
h = httplib2.Http()
result = json.loads(h.request(url, 'GET')[1])
# If there was an error in the access token info, abort.
if result.get('error') is not None:
response = make_response(json.dumps(result.get('error')), 500)
response.headers['Content-Type'] = 'application/json'
return response
# Verify that the access token is used for the intended user.
if result['user_id'] != gplus_id:
response = make_response(
json.dumps("Token's user ID doesn't match given user ID."), 401)
response.headers['Content-Type'] = 'application/json'
return response
...
However, the flow stops at if result['user_id'] != gplus_id:, saying "Token's user ID doesn't match given user ID.". result['user_id'] is a valid users ID, but gplus_id is None.
The line gplus_id = request.args.get('gplus_id') is expecting the GET args to contain 'gplus_id', but they only contain 'state'. Is this a problem with my javascript connectServer function? Should I include 'gplus_id' there? Surely I don't know it at that point. Or something else?
Similar to this question, I believe this is an issue with incomplete / not up to date / inconsistent documentation.
Where https://developers.google.com/+/web/signin/server-side-flow suggests that gplus_id will be returned in the GET arguments, this is not the case for the flow I was using.
I found my answer in https://github.com/googleplus/gplus-quickstart-python/blob/master/signin.py, which includes this snippet:
# An ID Token is a cryptographically-signed JSON object encoded in base 64.
# Normally, it is critical that you validate an ID Token before you use it,
# but since you are communicating directly with Google over an
# intermediary-free HTTPS channel and using your Client Secret to
# authenticate yourself to Google, you can be confident that the token you
# receive really comes from Google and is valid. If your server passes the
# ID Token to other components of your app, it is extremely important that
# the other components validate the token before using it.
gplus_id = credentials.id_token['sub']

Categories

Resources