I am trying to request data from an endpoint in the twitter enterprise API (/totals)
I have been successfull in retrieving data from /historical using oauth 1.0a
And to my eye the response I get from the authorization looks correct
{
"statusCode": 403,
"body": {
"errors": [
"Forbidden to access tweets: 123456789,
]
},
"headers": {
"date": "Tue, 10 Aug 2021 12:17:56 GMT",
"server": "tsa_o",
"set-cookie": [
"personalization_id=\"XXXXXXX/xxxxxx==\"; Max-Age=63072000; Expires=Thu, 10 Aug 2023 12:17:57 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None",
"guest_id=v1%3A162859787755489778; Max-Age=63072000; Expires=Thu, 10 Aug 2023 12:17:57 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None"
],
"content-type": "application/json; charset=utf-8",
"x-request-id": "8db9ed7b269fe772",
"cache-control": "no-cache, no-store, max-age=0",
"content-length": "189",
"content-encoding": "gzip",
"strict-transport-security": "max-age=631138519",
"x-connection-hash": "3581ca69fa8583875f011a335e831ea0e9a1e6fbe14f2fb37d473825116bea23",
"connection": "close"
},
"request": {
"uri": "https://data-api.twitter.com/insights/engagement/totals",
"method": "POST",
"headers": {
"Accept-Encoding": "gzip",
"accept": "application/json",
"content-type": "application/json",
"content-length": 424,
"Authorization": "OAuth oauth_consumer_key=\"XXXXXXXXXXxxxxx\",oauth_nonce=\"xXXXXXX\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1628597877\",oauth_token=\"xxxxxxxXXXXXXX\",oauth_version=\"1.0\",oauth_signature=\"xXXXXXXXXXX\""
}
}
}
Code:
Authorization code below,
async getRequest({ oauth_token, oauth_token_secret }, params) {
const oAuthConfig = {
consumer_key: "xx",
consumer_secret: "xx",
token: oauth_token,
token_secret: oauth_token_secret,
}
const req = await post({
url: new URL(
"https://data-api.twitter.com/insights/engagement/totals"
),
headers: { "Accept-Encoding": "gzip" },
oauth: oAuthConfig,
body: params,
json: true,
gzip: true,
})
if (req.body) {
return req.body
} else {
throw new Error("Cannot get an OAuth request token")
}
}
This method is then called as per docs with the information needed, however as you can see from the output I get Forbidden to access tweets,
async getMetrics(tweet_ids, info, oldest) {
const accessToken = {
oauth_token: info.tokens.accessToken,
oauth_token_secret: info.tokens.refreshToken,
user_id: info.id,
screen_name: info.username,
}
try {
let params = {
tweet_ids: tweet_ids,
engagement_types: [
"impressions",
"engagements",
// "favorites",
// "retweets",
// "quote_tweets",
// "replies",
// "video_views"
],
groupings: {
"types-by-tweet-id": {
group_by: [
"tweet.id",
"engagement.type",
],
},
},
}
const response = await this.getRequest(accessToken, params)
console.log(response)
if (response.hasOwnProperty("errors")) {
if (response.unavailable_tweet_ids) {
}
throw response.errors
}
return response
} catch (e) {
console.error(e)
throw e
}
}
I am at a total loss to why this is not working, as it works like I described with the /historical endpoint, can anyone spot the error in the authentication code as per docs Forbidden access means per docs that there is something wrong with the authentication
Docs: https://developer.twitter.com/en/docs/twitter-api/enterprise/engagement-api/api-reference/post-insights-engagement#errors
Related
So I first integrated Amadeus for flight booking and everything went well but problem arrived when I started integrating hotel booking. If I use nodejs library of Amadeus, I get a response that my access token is invalid. This is my code of nestjs service and response.
async hotelSearch(data) {
try {
var amadeus = new Amadeus({
clientId: process.env.API_KEY,
clientSecret: process.env.API_SECRET
});
return await amadeus.shopping.hotelOffers.get(data)
} catch (error) {
return error;
}
}
And this is the response.result -
"result": {
"errors": [
{
"code": 38190,
"title": "Invalid access token",
"detail": "The access token provided in the Authorization header is invalid",
"status": 401
}
]
},
"parsed": true
},
"description": [
{
"code": 38190,
"title": "Invalid access token",
"detail": "The access token provided in the Authorization header is invalid",
"status": 401
}
],
"code": "AuthenticationError"
}
How can I get Invalid Access Token error when I am using the library for it?? Anyway, after facing this issue I decided to use axios instead but still got no success.
async getToken(): Promise<{access_token: string}> {
try {
const data = qs.stringify({
client_id: process.env.API_KEY,
client_secret: process.env.API_SECRET,
grant_type: 'client_credentials'
});
const config:AxiosRequestConfig = {
method: 'post',
maxBodyLength: Infinity,
url: 'https://test.api.amadeus.com/v1/security/oauth2/token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: data
};
return await axios(config)
.then((response) => {
return((response.data));
})
.catch((error) => {
console.log(error);
});
} catch (error) {
return error;
}
}
async hotelSearch(data) {
try {
const tokenData=await this.getToken()
const refreshToken='Bearer '+ ( tokenData).access_token
console.log('token', refreshToken)
const config:AxiosRequestConfig = {
method: 'get',
maxBodyLength: Infinity,
url: 'https://test.api.amadeus.com/v1/reference-data/locations/hotels/by-city',
data: data,
headers: {'Authorization':refreshToken},
};
return await axios(config).then((response) => {
return(JSON.stringify(response.data));
})
.catch((error) => {
return(error);
});
// var amadeus = new Amadeus({
// clientId: process.env.API_KEY,
// clientSecret: process.env.API_SECRET
// });
// return await amadeus.shopping.hotelOffers.get(data)
} catch (error) {
return error;
}
}
And this is the response I got this time.
{
"message": "Request failed with status code 400",
"name": "Error",
"stack": "Error: Request failed with status code 400\n at createError (E:\\travel-portal\\travel-portal\\node_modules\\axios\\lib\\core\\createError.js:16:15)\n at settle (E:\\travel-portal\\travel-portal\\node_modules\\axios\\lib\\core\\settle.js:17:12)\n at IncomingMessage.handleStreamEnd (E:\\travel-portal\\travel-portal\\node_modules\\axios\\lib\\adapters\\http.js:322:11)\n at IncomingMessage.emit (node:events:525:35)\n at endReadableNT (node:internal/streams/readable:1359:12)\n at processTicksAndRejections (node:internal/process/task_queues:82:21)",
"config": {
"transitional": {
"silentJSONParsing": true,
"forcedJSONParsing": true,
"clarifyTimeoutError": false
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": null,
"headers": {
"Accept": "application/json, text/plain, */*",
"Authorization": "Bearer CMHEjXBrpzE7YxF9O7GKygCtzCxO",
"Content-Type": "application/json",
"User-Agent": "axios/0.26.1",
"Content-Length": 117
},
"method": "get",
"url": "https://test.api.amadeus.com/v1/reference-data/locations/hotels/by-city",
"data": "{\"cityCode\":\"DEL\",\"radius\":\"5\",\"radiusUnit\":\"KM\",\"checkInDate\":\"2023-03-10\",\"checkOutDate\":\"2023-03-11\",\"adults\":\"2\"}"
},
"status": 400
}
I have cross-checked the payload. The bearer token is all good when I console it and even I checked the request with fiddler and there too header and data are getting passed. Any help to get this work through either of the method is really appreciated.
The amadeus.shopping.hotelOffers.get() endpoint has been decommissioned so you won't be able to use it. Install the latest version of the Node library and use the new Hotel Search endpoint as below:
var Amadeus = require(amadeus);
var amadeus = new Amadeus({
clientId: 'YOUR_API_KEY',
clientSecret: 'YOUR_API_SECRET'
});
// Get list of available offers in specific hotels by hotel ids
amadeus.shopping.hotelOffersSearch.get({
hotelIds: 'RTPAR001',
adults: '2'
}).then(function (response) {
console.log(response);
}).catch(function (response) {
console.error(response);
});
You can also check the migration guide for more details and how to use the new Hotel Search version.
I have a nestjs application which handles some marketing automation tasks.
I have set up datadog and sentry and I keep getting errors.
When I replay the bodies locally, I get no errors. I'm a bit stuck here.
The error I get on sentry is the following (i'm stringifying the error as additional data)
{
"success": false,
"message": "Bad Request",
"errorCode": 400,
"context": {
"req": {
"method": "PUT",
"url": "https://api.pipedrive.com/v1/persons/84653?api_token=my_token",
"data": {},
"headers": {
"user-agent": "Pipedrive-SDK-Javascript-16.0.3",
"content-type": "application/json",
"accept": "application/json"
}
},
"header": {
"date": "Thu, 22 Sep 2022 22:01:46 GMT",
"content-type": "application/json",
"transfer-encoding": "chunked",
"connection": "close",
"cf-ray": "74ee5231de24f40b-LHR",
"access-control-allow-origin": "*",
"cache-control": "no-cache",
"content-encoding": "gzip",
"strict-transport-security": "max-age=31536000; includeSubDomains",
"vary": "Accept-Encoding",
"cf-cache-status": "DYNAMIC",
"access-control-expose-headers": "X-RateLimit-Remaining, X-RateLimit-Limit, X-RateLimit-Reset",
"badi": "Routing: eu-central-1=>eu-central-1; Version: 8cce; Host: bari;",
"x-content-type-options": "nosniff",
"x-correlation-id": "5ccf217c-aee7-4d8f-ab89-70277fb5b4f7",
"x-daily-requests-left": "6918",
"x-frame-options": "SAMEORIGIN",
"x-ratelimit-limit": "40",
"x-ratelimit-remaining": "37",
"x-ratelimit-reset": "2",
"x-xss-protection": "1; mode=block",
"set-cookie": [
"__cf_bm=bqPOYf9wW8omTTIvIQnhXgCqxmqexoZCvl0tRkmINBo-1663884106-0-AWQN9mC/Fq+ELcoe7Pfp2aTXcv9JapLJYfrMsUbE3+lOJGgva9hLWHPLGy97S7tDNszaDW5tew4//3R2mVz9bcI=; path=/; expires=Thu, 22-Sep-22 22:31:46 GMT; domain=.pipedrive.com; HttpOnly; Secure; SameSite=None"
],
"server": "cloudflare",
"alt-svc": "h3=\":443\"; ma=86400, h3-29=\":443\"; ma=86400"
},
"status": 400,
"text": "{\"success\":false,\"error\":\"Bad request\",\"error_info\":\"Please check developers.pipedrive.com for more information about Pipedrive API.\",\"data\":null,\"additional_data\":null}"
},
"errorInfo": "Please check developers.pipedrive.com for more information about Pipedrive API."
}
It seems related to making a PUT request on pipedrive with an empty body.
However my code for that is the following:
async updatePerson(id: number, person: IPipedrivePersonDto): Promise<PipedrivePerson> {
if (isEmpty(person)) {
throw new Error(`Can't update a person with no body`);
}
const personApi = new this.pipeDriveClient.PersonsApi();
const opts = Pipedrive.UpdatePerson.constructFromObject(person);
if (isEmpty(opts)) {
throw new Error(`Can't update a person with no body: ` + JSON.stringify(person));
}
const { data } = (await personApi.updatePerson(id, opts)) as PersonResponse;
return data;
}
And when I do trick my body to get an empty body it gets caught.
So now, sentry does not give me the entire stack trace, the list of lines of code executed. That might help me.
How can I get that ?
How else can I debug something I can't reproduce?
I also suspect the pipedrive node js client to make some hidden PUT requests, cause there is only the aforementioned snippet that handles it in my code.
Here is the full code of my http exception filter on nestjs, maybe I can pipm it somehow to get more details:
import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '#nestjs/common';
import { SentryService } from '#ntegral/nestjs-sentry';
import { Request, Response } from 'express';
import { CustomLoggerService } from 'src/core/logger/logger.service';
import { PipedriveResponseException } from 'src/thirdParties/pipedrive/pipedrive.exception';
import { SlackResponseException } from 'src/thirdParties/slack/slack.exception';
import { injectRecord } from 'src/utils/datadog';
#Catch()
export class HttpExceptionFilter implements ExceptionFilter {
constructor(private readonly sentry: SentryService, private readonly logger: CustomLoggerService) {}
private logAndSendResponse(
exception: PipedriveResponseException | HttpException,
request: Request,
response: Response,
jsonResponse: object,
message: string | null,
status: number,
) {
const record = injectRecord({ ...jsonResponse, stack: exception.stack }, 'error');
this.logger.logger.error(`${request.method} ${request.originalUrl}`, record, exception);
this.sentry.instance().setExtra('response', jsonResponse);
this.sentry.instance().setTag('message', message);
response.status(status).json(jsonResponse);
}
catch(exception: PipedriveResponseException | HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const pipeDriveException = exception as PipedriveResponseException;
const slackException = exception as unknown as SlackResponseException;
const globalException = exception as HttpException;
const baseResponse = {
timestamp: new Date().toISOString(),
path: request.url,
};
this.sentry.instance().setTag('url', request.url);
this.sentry.instance().setTag('method', request.method);
this.sentry.instance().setExtra('stringified-error', JSON.stringify(exception));
// Catch slack exceptions
if (slackException.code && slackException.data?.error) {
const status = 400;
const message = slackException?.data?.error || null;
const jsonResponse = {
...baseResponse,
statusCode: status,
message: message,
};
this.logAndSendResponse(exception, request, response, jsonResponse, message, status);
// Catch pipedrive exceptions
} else if (pipeDriveException.context && pipeDriveException.errorCode && pipeDriveException.errorInfo) {
const status = pipeDriveException.errorCode;
const message = pipeDriveException.context?._body?.error || null;
const jsonResponse = {
...baseResponse,
statusCode: status,
message: message,
};
this.logAndSendResponse(exception, request, response, jsonResponse, message, status);
} else {
const jsonResponse = {
...baseResponse,
exception,
};
this.logAndSendResponse(exception, request, response, jsonResponse, globalException.message, 500);
}
this.sentry.instance().captureException(exception);
}
}
Thanks for your help :)
I'm struggling a bit within a small project for fetching and creating (via POST) an entry, where I have on one side:
A GraphQL server (apollo)
A react app, using useQuery hook
A rest API, where the resolvers of the Apollo project is fetching data with async JS functions
I have the following obstacles:
I'm not able to post an entry for the rest API via GraphQl query or Mutation.
I have success in this post request:
POST https://technologytalents.io/space-cats/index.php/openapi/create_channel_entry
Accept: application/json
Content-Type: application/x-www-form-urlencoded
User-Agent: axios/0.21.1
channel_id=1&url_title=Blas&entry_date=12345678&title=Dooom&session_id=b288ea559b20c584a3a793685ceb20c240c26569
The success response of this is:
{entry_id: 2}
In my graphQL schema:
input entryIntput {
url_title: String
title: String
channel_id: Int
entry_date: Int
}
type postEntrySuccess {
entry_id: Int
}
type Mutation {
createEntry(input: entryIntput): postEntrySuccess
}
and in the resolvers:
Mutation: {
createEntry: async (_, entry) => await channelEntriesService.postEntry(entry)
}
my ChannelEntriesSerives looks like:
const axios = require('axios')
const authenticate = require('./authenticate')
class ChannelEntries {
constructor(options) {
this._options = options
}
async getEntries() {
const auth = await authenticate.auth()
const patch = {
...options,
url: `${options.url}/get_channel_entries?channel_id=1&where[status]=open&session_id=${auth.session_id}`
}
const response = await axios(patch)
return response.data
}
async postEntry(entry = { url_title: 'Blas', title: 'Dooom', entry_date: Date.now(), channel_id: 1 }) {
const auth = await authenticate.auth()
const patch = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
url: `${this._options.url}/create_channel_entry?channel_id=${entry.channel_id}&url_title=${entry.url_title}&title=${entry.title}&entry_date=${entry.entry_date}_id=${auth.session_id}`
}
const response = await axios.request(patch)
return response.data
}
}
const options = {
method: 'GET',
url: 'https://technologytalents.io/space-cats/index.php/openapi',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}
module.exports = instance = new ChannelEntries(options)
When I try to execute the mutation on the GraphQl studio:
mutation CreateEntry($createEntryInput: entryIntput) {
createEntry(input: $createEntryInput) {
entry_id
}
}
I've got an error:
{
"errors": [
{
"message": "Request failed with status code 400",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createEntry"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"config": {
"url": "https://technologytalents.io/space-cats/index.php/openapi/create_channel_entry?channel_id=undefined&url_title=undefined&title=undefined&entry_date=undefined_id=b3c77d7c74b0cc10de61c90f8e1a34b30e454f7a",
"method": "post",
"headers": {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "axios/0.21.1"
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1
}
}
}
}
],
"data": {
"createEntry": null
}
}
What I'm doing wrong?
I found the reason for the error, and this is due to my rusty Axios basics. The config of an Axios request should have "data" property, so changing it to
const patch = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
url: `${this._options.url}/create_channel_entry`,
data: `channel_id=${entry.channel_id}&url_title=${entry.url_title}&title=${entry.title}&entry_date=${entry.entry_date}&session_id=${auth.session_id}`
}
returns the correct response.
The other issue is just a correct mapping of the response with graphql schema.
I'm trying to build react-native fuction to make POST request to an API using Axios. The function seems to work but i keep getting the response as undefined. I've tested POST request with Postman, it works normally.
{
"CaThuHoiList": [
{
"NGAY": "20-01-2020",
"TH_ID": 33,
"CA": 1,
"CT_DONVI_ID": 78,
"CREATE_BY": 4797,
"TRANG_THAI": "HT",
"CREATE_DATE": "20-01-2020 00:00",
"KHO_ID": null,
"LOAI": "TT"
},
{
"NGAY": "20-01-2020",
"TH_ID": 34,
"CA": 1,
"CT_DONVI_ID": 78,
"CREATE_BY": 4797,
"TRANG_THAI": "BD",
"CREATE_DATE": "20-01-2020 00:00",
"KHO_ID": null,
"LOAI": "TL"
}
],
"Status": 1,
"Message": ""
}
However i couldn't get the same response (undefined) while running my function:
onPostJson = () => {
axios.post('https://10.1.127.17:11111/vpdu/get-ca-thu-hoi', {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
FromDate: "01-Jan-2020",
ToDate: "01-Feb-2020",
Ca: 1
})
})
.then(function (response) {
data = response;
console.log(data); \\Storing response in data still getting undefined
return response;
})
.catch(function (error) {
console.log(error);
});
}
Could anyone tell me what is the problem? Thanks in advance.
You need to have data pulled out. I have done the changes. You may check out.
onPostJson = () => {
let configObject = {
"url": "https://10.1.127.17:11111/vpdu/get-ca-thu-hoi",
"method": "post",
"headers": {
'Content-Type': 'application/json'
},
"data":{
"FromDate": "01-Jan-2020",
"ToDate": "01-Feb-2020",
"Ca": 1
}
}}
axios.request(configObject ).then((res) => {
console.log("react1: ", res);
console.log("react2: ", res.data);
})
}
const inserrequest=async () => {
let addreq = await axios.post('http://xxxxxx..//Employee/PostInsertrequest',
{
ReqEmpCode: 'xxxxxx',
});
console.warn(JSON.stringify(addreq.data));
}
I have an Elasticsearch instance that I can successfully query from Postman. I'm now trying to execute that same query from JavaScript via Axios. However, when I send my Axios request, I receive a 400 error. Currently, my request looks like this:
try {
let authorizationToken = getAuthToken();
let parameters = {
headers: {
"cache-control": "no-cache",
"Content-Type": "application/json",
"Authorization": "Basic " + authorizationToken
},
body: {
"size": 100,
"query": {
"bool": {
"filter": [
{ "range": {
"created_at": {"gte":"now-10m"}
} }
]
}
}
}
};
let url = 'https://my-cluster-address/my-index/_search?scroll=10m';
let res = await axios.post(url, parameters);
console.log('all good');
} catch (ex) {
console.log(ex);
}
What is wrong with my query? Why am I getting a 400 error?