Amazon Sp-Api createFeedDocument, No Responding (Node.js) / And InvalidInput-contentType Error - node.js

I am trying to call the createFeedDocument operation to sp-api. But I never get a response.
Here is my signedRequest:
{
path: '/feeds/2020-09-04/documents',
method: 'POST',
host: 'sellingpartnerapi-fe.amazon.com',
region: 'us-west-2',
service: 'execute-api',
headers: {
'User-Agent': 'MyAmazonApp/1.0 (Language=JavaScript;)',
'x-amz-access-token': 'Atzasd61as689d1a1f89a189198ea1f891ad89d1e891f89ae189f189165',
Accept: 'application/json',
'Accept-Charset': 'utf-8',
Host: 'sellingpartnerapi-fe.amazon.com',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
'Content-Length': 58,
'X-Amz-Security-Token': 'Fwa***********************************************',
'X-Amz-Date': '20210404T230040Z',
Authorization: 'AWS4-HMAC-SHA256 Credential=ASIASEECTM3DHQOSTQ4M/20210404/us-west-2/execute-api/aws4_request, SignedHeaders=accept;accept-charset;content-length;content-type;host;x-amz-access-token;x-amz-date;x-amz-security-token, Signature=f***********************************************e'
},
body: '{"contentType":"text/tab-separated-values; charset=UTF-8"}'
}
And if I tried to call this operation without body it gives the error shown below:
{
"statusCode": 400,
"res": {
"errors": [
{
"code": "InvalidInput",
"message": "One or more required parameters missing",
"details": "contentType;"
}
]
}
}

Your Content-Type header should be application/json

Related

Nodemailer 3LO OAuth give GaxiosError: unauthorized_client

In emailTransporter.js my code like below.
const nodemailer = require('nodemailer');
const { google } = require("googleapis");
const path = require('path');
const OAuth2 = google.auth.OAuth2;
require('dotenv').config({path: path.join(__dirname, '.env')});
const oauth2Client = new OAuth2(
process.env.CLIENT_ID, // ClientID
process.env.CLIENT_SECRET, // Client Secret
"https://developers.google.com/oauthplayground" // Redirect URL
);
oauth2Client.setCredentials({
refresh_token: process.env.REFRESH_TOKEN
});
const accessToken = oauth2Client.getAccessToken();
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
type: "OAuth2",
user: process.env.USER_EMAIL,
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
refreshToken: process.env.REFRESH_TOKEN,
accessToken: accessToken
},
tls: {
rejectUnauthorized: false
}
});
module.exports = transporter;
In auth.js I use emailTransporter exports from emailTransporter.js to send some email options. But node give me error like this:
D:\nodejs\node_modules\gaxios\build\src\gaxios.js:129
throw new common_1.GaxiosError(Request failed with status code ${translatedResponse.status}, opts, translatedResponse);
^
GaxiosError: unauthorized_client
at Gaxios._request (D:\nodejs\node_modules\gaxios\build\src\gaxios.js:129:23)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async OAuth2Client.refreshTokenNoCache (D:\nodejs\node_modules\google-auth-library\build\src\auth\oauth2client.js:174:21)
at async OAuth2Client.refreshAccessTokenAsync (D:\nodejs\node_modules\google-auth-library\build\src\auth\oauth2client.js:198:19)
at async OAuth2Client.getAccessTokenAsync (D:\nodejs\node_modules\google-auth-library\build\src\auth\oauth2client.js:227:23) {
response: {
config: {
method: 'POST',
url: 'https://oauth2.googleapis.com/token',
data: 'refresh_token=1%2F%2F04PvTQnD4_86nCgYIARAAGAQSNwF-L9IrTdRMaV9mdIMhyEhFeJeKGSvqYnbgkCw-18aF7ZFmRgpWoWiQM3EXozwMiXzvfYwmAwc&client_id=543495663437-d59lg6u1a77o9a2uinf83idb0md991l9.apps.googleusercontent.com&client_secret=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&grant_type=refresh_token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'google-api-nodejs-client/7.11.0',
'x-goog-api-client': 'gl-node/16.13.2 auth/7.11.0',
Accept: 'application/json'
},
paramsSerializer: [Function: paramsSerializer],
body: 'refresh_token=1%2F%2F04PvTQnD4_86nCgYIARAAGAQSNwF-L9IrTdRMaV9mdIMhyEhFeJeKGSvqYnbgkCw-18aF7ZFmRgpWoWiQM3EXozwMiXzvfYwmAwc&client_id=543495663437-d59lg6u1a77o9a2uinf83idb0md991l9.apps.googleusercontent.com&client_secret=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&grant_type=refresh_token',
validateStatus: [Function: validateStatus],
responseType: 'json'
},
data: { error: 'unauthorized_client', error_description: 'Unauthorized' },
headers: {
'alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"',
'cache-control': 'no-cache, no-store, max-age=0, must-revalidate',
connection: 'close',
'content-encoding': 'gzip',
'content-type': 'application/json; charset=utf-8',
date: 'Wed, 19 Jan 2022 03:47:31 GMT',
expires: 'Mon, 01 Jan 1990 00:00:00 GMT',
pragma: 'no-cache',
server: 'scaffolding on HTTPServer2',
'transfer-encoding': 'chunked',
vary: 'Origin, X-Origin, Referer',
'x-content-type-options': 'nosniff',
'x-frame-options': 'SAMEORIGIN',
'x-xss-protection': '0'
},
status: 401,
statusText: 'Unauthorized',
request: { responseURL: 'https://oauth2.googleapis.com/token' }
},
config: {
method: 'POST',
url: 'https://oauth2.googleapis.com/token',
data: 'refresh_token=1%2F%2F04PvTQnD4_86nCgYIARAAGAQSNwF-L9IrTdRMaV9mdIMhyEhFeJeKGSvqYnbgkCw-18aF7ZFmRgpWoWiQM3EXozwMiXzvfYwmAwc&client_id=543495663437-d59lg6u1a77o9a2uinf83idb0md991l9.apps.googleusercontent.com&client_secret=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&grant_type=refresh_token', headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'google-api-nodejs-client/7.11.0',
'x-goog-api-client': 'gl-node/16.13.2 auth/7.11.0',
Accept: 'application/json'
},
paramsSerializer: [Function: paramsSerializer],
body: 'refresh_token=1%2F%2F04PvTQnD4_86nCgYIARAAGAQSNwF-L9IrTdRMaV9mdIMhyEhFeJeKGSvqYnbgkCw-18aF7ZFmRgpWoWiQM3EXozwMiXzvfYwmAwc&client_id=543495663437-d59lg6u1a77o9a2uinf83idb0md991l9.apps.googleusercontent.com&client_secret=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&grant_type=refresh_token', validateStatus: [Function: validateStatus],
responseType: 'json'
},
code: '401'
}
In https://developers.google.com/oauthplayground/, I have to choose option Use your own credentials at top right side. Fill in the cliendId and clientSecret and it already worked.

Home Assistant - Request failed Error code 400

I made this function to make it possible to send announcements to my google home mini but im getting error code 400 (Bad Request) nonstop. I tried using multiple approaches to this.
In Home-Assistant, i have setup my Google Home and can play media through it but whenever i try it with the "google_say" API of Home-Assistant it doesn't work.
I also tried calling the Home-Assistant API over my Phone using an App called "API Client" but i got the same response.
function ttsGoogleHome(text) {
var ttsUrl = "http://127.0.0.1:8123/api/services/tts/google_say?api_password=<MY_PASSWORD>"
var varToken = "<MY_TOKEN>"
var postData = {"entity_id": "media_player.david", "message": `${text}`};
let axiosConfig = {
headers: {
'authorization': `Bearer ${varToken}`,
'Content-Type': 'application/json',
"Access-Control-Allow-Origin": "*",
}
};
axios.post(ttsUrl, postData, axiosConfig)
.then((res) => {
console.log("RESPONSE RECEIVED: ", JSON.stringify(res));
})
.catch((err) => {
console.log("AXIOS ERROR: ", JSON.stringify(err));
})
}
This is the response i get in the server:
{
"message": "Request failed with status code 400",
"name": "Error",
"stack": "Error: Request failed with status code 400\n
at createError (/home/pi/nodejs/node_modules/axios/lib/core/createError.js:16:15)\n
at settle (/home/pi/nodejs/node_modules/axios/lib/core/settle.js:17:12)\n
at IncomingMessage.handleStreamEnd (/home/pi/nodejs/node_modules/axios/lib/adapters/http.js:260:11)\n
at IncomingMessage.emit (events.js:388:22)\n
at endReadableNT (internal/streams/readable.js:1336:12)\n
at processTicksAndRejections (internal/process/task_queues.js:82:21)",
"config": {
"url": "http://127.0.0.1:8123/api/services/tts/google_say?api_password=<MY_PASSWORD>",
"method": "post",
"data": "{\"entity_id\":\"media_player.david\",\"message\":\"Erste Stunde Fach Deutsch Lehrer Schemmer Raum Schemmer\"}",
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json;charset=UTF-8",
"authorization": "Bearer <MY_TOKEN>",
"Access-Control-Allow-Origin": "*",
"User-Agent": "axios/0.21.1",
"Content-Length": 103
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1
}
}
I found my error.
I used the wrong api link
here is the correct way to call it.
function ttsGoogleHome(text) {
var ttsUrl = "http://127.0.0.1:8123/api/services/tts/google_translate_say?api_password=APIPASSWORD"
var varToken = "TOKEN"
var postData = `{"entity_id": "media_player.david", "message": "${text}", "language": "de"}`;
let axiosConfig = {
data: null,
headers: {
'authorization': `Bearer ${varToken}`,
'Content-Type': 'application/json',
"Access-Control-Allow-Origin": "*",
}
};
axios.post(ttsUrl, postData, axiosConfig)
.then((res) => {
console.clear();
console.info("RESPONSE RECEIVED: ", JSON.stringify(res));
})
.catch((err) => {
console.clear();
console.error("AXIOS ERROR: ", JSON.stringify(err));
})
}
also here is my configuration.yaml:
# Configure a default steup of Home Assistant (frontend, api, etc)
# Text to speech
tts:
- platform: google_translate
- language: "de"
- service_name: google_say
-base_url: http://192.168.0.176:8123
group: !include groups.yaml
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
homeassistant:
auth_providers:
- type: legacy_api_password
api_password: !secret http_password

API Gateway randomly switching responses from 403 to 404

I have API Gateway set up to serve some files from S3 bucket with Lambda. When I try to request non-existing files, API Gateway sometimes responds with 403 Forbidden (most of the times and doesn't even trigger Lambda function) and sometimes with 404 Not Found error (I'd like to trigger 404 in such cases).
My Lambda function is very simple:
exports.handler = async event => {
try {
const Bucket = 'testing-bucket';
const Key = `${event.documentType}/${event.requestParams.document}`;
const file = await s3.getObject({ Bucket, Key }).promise();
return {
body: file.Body.toString('base64'),
headers: {
'Content-Disposition': `attachment; filename=test.jpg`,
'Content-Length': file.ContentLength,
'Content-Type': file.ContentType,
},
statusCode: 200,
isBase64Encoded: true,
};
} catch (e) {
return {
body: JSON.stringify({ message: `[${e.code}] ${e.message}` }),
statusCode: e.statusCode,
};
}
};
IAM Role attached to Lambda function is configured in this way:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::testing-bucket",
"arn:aws:s3:::testing-bucket/*"
]
}
]
}
Caching is completely disabled in API Gateway and the command I've been trying to test this out is:
curl -X GET -H 'Authorization: 123xyz' -H 'Accept: image/jpeg' -H 'Cache-Control: no-cache' -I https://test.com/existing_folder/non-existing-file.xxx
Responses are:
HTTP/2 403
content-type: application/json
content-length: 60
date: Mon, 07 Oct 2019 10:32:30 GMT
x-amzn-requestid: ae870104-9045-4c23-9794-226992bad591
x-amzn-errortype: AccessDeniedException
x-amz-apigw-id: BMAZwGSyoAMFftw=
x-cache: Error from cloudfront
via: 1.1 ccf34ecc11e5579d8083b17d9d39a622.cloudfront.net (CloudFront)
x-amz-cf-pop: LHR62-C2
x-amz-cf-id: zgtgfJX9TQLcI8F2RLWdgTz-RN_1j7MXblQ1498ucoeFY3dhjitOdg==
and
HTTP/2 404
content-type: application/json
content-length: 59
date: Mon, 07 Oct 2019 10:32:31 GMT
x-amzn-requestid: 2de49681-4f21-4cd1-989c-9b36327badb1
x-amz-apigw-id: BMAZ5E52IAMFwEg=
x-amzn-trace-id: Root=1-5d9b143f-aadf0a24a5f60f4c939b77c0;Sampled=0
x-cache: Error from cloudfront
via: 1.1 be00537a2361673ea48963d6e04d04a1.cloudfront.net (CloudFront)
x-amz-cf-pop: LHR62-C2
x-amz-cf-id: 9VI26GH3-ZuJSQrEt5Fc7EjuMt8IV0TPzPwna8dvvr6UtsgiqwwIkw==
How to make API Gateway respond in consistent way?
UPDATE:
After observing API Gateway logs and trying to spam the same curl command for existing and non-existing files couple of times in a row, this was the output for non-existing file (timestamps are intact):
# curl -X GET -H 'Authorization: 123xyz' -H 'Accept: image/jpeg' -H 'cache-control: private, no-cache, no-store, max-age=1, s-maxage=1' https://my.url/foo/nobar
{
"requestId": "d19602e8-3a32-4445-b9e6-99f05a59fac4",
"ip": "redacted",
"caller": "-",
"user": "-",
"requestTime": "08/Oct/2019:00:05:03 +0000",
"httpMethod": "GET",
"resourcePath": "/foo/{bar}",
"status": "404",
"protocol": "HTTP/1.1",
"responseLength": "59"
}
# and
{
"requestId": "b33bf6c7-55db-4e1f-b4e4-b1e826139556",
"ip": "redacted",
"caller": "-",
"user": "-",
"requestTime": "08/Oct/2019:00:05:05 +0000",
"httpMethod": "GET",
"resourcePath": "/foo/{bar}",
"status": "403",
"protocol": "HTTP/1.1",
"responseLength": "60"
}
and for existing file:
# curl -X GET -H 'Authorization: 123xyz' -H 'Accept: image/jpeg' -H 'cache-control: private, no-cache, no-store, max-age=1, s-maxage=1' https://my.url/foo/bar
{
"requestId": "122ef31e-c587-470c-a0b5-51c6d9838fe4",
"ip": "redacted",
"caller": "-",
"user": "-",
"requestTime": "07/Oct/2019:23:58:35 +0000",
"httpMethod": "GET",
"resourcePath": "/foo/{bar}",
"status": "403",
"protocol": "HTTP/1.1",
"responseLength": "60"
}
# and then later
{
"requestId": "c8ad1b40-006f-4d03-9d10-c6d91e366380",
"ip": "redacted",
"caller": "-",
"user": "-",
"requestTime": "07/Oct/2019:23:59:58 +0000",
"httpMethod": "GET",
"resourcePath": "/foo/{bar}",
"status": "200",
"protocol": "HTTP/1.1",
"responseLength": "80280"
}
I finally got some time to get back to this issue and it looks like the problem was all along in "authorizer" function which had caching enabled, once disabled, my responses started to respond in a consistent way.
You can manage the response yourself. You can check if the file doesn't exist after your await and respond a 404. Something like this: (Code not tested)
exports.handler = async event => {
try {
const Bucket = 'testing-bucket';
const Key = `${event.documentType}/${event.requestParams.document}`;
const file = await s3.getObject({ Bucket, Key }).promise();
if (!file) {
return {
body: {error: 'File not found'},
headers: {
'Content-Type': 'application/json'
}
statusCode: 400,
};
}
return {
body: file.Body.toString('base64'),
headers: {
'Content-Disposition': `attachment; filename=test.jpg`,
'Content-Length': file.ContentLength,
'Content-Type': file.ContentType,
},
statusCode: 200,
isBase64Encoded: true,
};
} catch (e) {
return {
body: JSON.stringify({ message: `[${e.code}] ${e.message}` }),
statusCode: e.statusCode,
};
}
};
So when I wrote my lambda to process s3 downloads, I did stick with promise chaining so that I could debug easier...have you tried the other method?
return s3.getObject({ Bucket, Key }).promise().then((s3Response) => {
console.log(s3Response.Body.toString());
}).catch((err) => {
console.log(err);
});
I have a feeling there is something happening in your promise that's causing it to come back to quick and it's failing or something along those lines.

Google calendar API - create event 400, Parse Error

Using python 3.6, requests==2.22.0
Trying to create an event: documentation link
url = 'https://www.googleapis.com/calendar/v3/calendars/{}/events'.format(calendar_id)
data = {
"summary": "CALENDAR TESTING",
"location": "Some fake location",
"description": "This is a test",
"start": {
"dateTime": "2019-10-09T09:00:00-07:00",
"timeZone": "America/Los_Angeles",
},
"end": {
"dateTime": "2019-10-09T10:00:00-07:00",
"timeZone": "America/Los_Angeles",
},
}
headers = {
'Authorization': 'Bearer {}'.format(self.access_token.get('token')),
'Accept': 'application/json',
'Content-Type': 'application/json',
}
response = requests.post(url, data=data, headers=headers)
print("Response: ", response)
j = response.json()
print("json: ", j)
Output:
Response: <Response [400]>
Raw Response: {'error': {'errors': [{'domain': 'global', 'reason': 'parseError', 'message': 'Parse Error'}], 'code': 400, 'message': 'Parse Error'}}
request body:
summary=CALENDAR+TESTING&location=Some+fake+location&description=This+is+a+test&start=dateTime&start=timeZone&end=dateTime&end=timeZone
request headers:
{'User-Agent': 'python-requests/2.22.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': 'application/json', 'Connection': 'keep-alive', 'Authorization': 'Bearer ******', 'Content-Type': 'application/json', 'Content-Length': '135'}
Stack posts that did not fix the issue:
stack post - re not setting content type, which I am
stack post - re apostrophes vs double quotes, I switched to double quotes still error
I did notice that the timezone information is missing from the request body, but I am not sure why, and if that is the issue.
I am looking into this post right now
A simple solution to fix the problem:
import json
response = requests.post(url, data=json.dumps(data), headers=headers)

how to i send HTTP request for sending notification in firebase?

To send a notification, you'll need to send the following HTTP request:
POST /fcm/send HTTP/1.1
Host: fcm.googleapis.com
Content-Type: application/json
Authorization: key=YOUR_SERVER_KEY
{
"notification": {
"title": "New chat message!",
"body": "There is a new message in FriendlyChat",
"icon": "/images/profile_placeholder.png",
"click_action": "http://localhost:5000"
},
"to":"YOUR_DEVICE_TOKEN"
}
how can I do this??
If you're using Node.JS, I suggest you look at the documentation for Firebase's Node.JS SDK instead of manually sending HTTP requests. There's the official documentation or this nice tutorial
If you still want to go for the plain HTTP method, you can use the request npm module
$ npm install request
then in your code :
const request = require('request');
request({
url: 'https://fcm.googleapis.com/fcm/send',
method: 'POST',
headers: {
"Content-Type": "application/json",
"Authorization": ['key', yourServerKey].join('=')
},
json: {
to: clientFirebaseToken,
notification: {
title: "Notification Title",
body: "This is a neat little notification, right ?"
}
});
Edit
From their GitHub
As of Feb 11th 2020, request is fully deprecated. No new changes are
expected to land. In fact, none have landed for some time.
If you use axios
axios({
method: 'post',
url: 'https://fcm.googleapis.com/fcm/send',
headers: {
"Content-Type": "application/json",
"Authorization": ['key', yourServerKey].join('=')
},
params: {
to: clientFirebaseToken,
notification: {
title: "Notification Title",
body: "Neat indeed !"
}
}
})
If you are using React JS/ React Native, using the Axios package it can be done very easily, the sample code is below, first, you have to register for firebase cloud messaging to get the authorization key
axios.post(
'https://fcm.googleapis.com/fcm/send',
{
data: {},
notification: {
title: "Sample text1",
body: "Sample text2",
image: "Sample text3",
},
to: '/topics/TopicName',
},
{
headers: {
Authorization:
'key=Authorization key from firebase',
},
},
)
.then(Response => {
console.log(Response.data);
});

Resources