I am using hapijs to create a simple route. The joi validation to check for header is throwing me an error although the header is passed
server.route({
method: 'GET',
path: '/myresponse',
handler: async (request: Request, reply) => {
try {
return reply.response('ddd');
} catch (error) {
const response = reply.response(error.data).code(error.statusCode);
return response;
}
},
options: {
validate: {
failAction: (request, h, err) => {
console.log(request.headers)
throw err;
},
headers: joi.object({
'cusHeader': joi.string().required()
}),
options: {
allowUnknown: true,
abortEarly: false
}
}
}
});
}
I want the user to pass the header cusHeader and its value should be of type string. I am passing the header in the postman request but it still throws me the below error,
{
"statusCode": 400,
"error": "Bad Request",
"message": "\"modalPath\" is required",
"validation": {
"source": "headers",
"keys": [
"cusHeader"
]
}
}
I don't know where I am wrong.
Related
i have created firebase cloud function to create contact in activeCampain. I have problem with catch errors from activeCampaign. If i sent request direct to activeCampain from insomnia everything works correctly, but if i use firebase cloud function with axios something goes wrong.
I will show the code.
I created a contact before and now it makes another query with the same data directly to activeCampaign api:
and i get expected result. But if made same request by firebase function i get properly status code but i don't see errors response from activeCampaign
FirebaseCloud function code:
const functions = require("firebase-functions");
const axios = require("axios");
const cors = require("cors")({ origin: true });
const addTagToContact = async (contactId: string, tagId: string) => {
try {
await axios({
method: "post",
url: "https://xyz.api-us1.com/api/3/contactTags",
headers: {
"Api-Token": "api-token",
},
data: {
contactTag: {
contact: contactId,
tag: tagId,
},
},
enter code here
});
} catch (e) {
console.error(e);
}
};
export const createNewContact = functions.https.onRequest((request: { body: any; }, response: { status: (arg0: number) => void; send: (arg0: { response?: unknown; status?: string; }) => void; }) => {
cors(request, response, async () => {
const newContactData = request.body;
if(!newContactData.email || !newContactData.fieldValues) {
return response.send({
response: 'No contact data provided'
})
}
try {
const responseActiveCampaign = await axios({
method: "post",
url: "https://xyz.api-us1.com/api/3/contacts",
headers: {
"Api-Token": "api-token",
"Content-Type": "application/json"
},
data: {
contact: newContactData,
},
});
console.log('response active campaign console log', responseActiveCampaign)
await addTagToContact(responseActiveCampaign.data.contact.id, "1")
return response.send({
response: responseActiveCampaign.data
})
} catch (error) {
console.error('catch error', error);
response.status(500);
response.send({
response: error,
});
}
});
});
response from this query:
How can i fix it? I would like to get error response from activeCampaign to use on my frontend
the catch should be like this:
catch (error) {
console.error('catch error', error);
response.status(500);
response.send({
response: error.response.data,
});
}
I'm trying to hit the Intercom API to retrieve a list of conversations and I can't figure out what's wrong. Here is the code:
const request=require('request')
const search_intercom=(admin_id, callback) => {
const options = {
url: 'https://api.intercom.io/conversations/search',
method: 'POST',
headers: {
Authorization: 'Bearer <token>'
},
json: {
query: JSON.stringify({
"field": "teammate_ids",
"operator": "=",
"value": admin_id
})
}
};
request(options, (error, {body} = {}) => {
if (error) {
callback('unable to connect to intercom API', undefined)
} else if (body.length === 0) {
callback('something went wrong', undefined)
} else {
callback(undefined, {
conversation_id: body.conversations[0].id,
client_name: body.conversations[0].source.author.name
})
console.log(body)
}
})
}
module.exports = search_intercom
I was able to wire it up correctly with the web server, so when I debug, options.json.query.admin_id does contain a valid id.
It breaks and says
conversation_id: body.conversations[0].id,
TypeError: Cannot read property '0' of undefined
Here is the content of the body response:
{
type: 'error.list',
request_id: '<some request_id>',
errors: [ { code: 'server_error', message: 'Server Error' } ]
}
Where should I look? I've tried a few different variations of options for sending the payload and I am guessing this is the issue, but I can't find the winning formula...
It looks like I got the body all wrong.
options should look like this instead:
const options = {
url: 'https://api.intercom.io/conversations/search',
method: 'POST',
headers: {
Authorization: 'Bearer <token>'
},
json: true,
body: {
query: {
"field": "teammate_ids",
"operator": "=",
"value": JSON.stringify(admin_id)
}
}
};
I'm working to send the data from my server to the webhook.
I'm using a "REQUEST" service, but I'm getting an error. My request hits there but I'm getting an error.
var request = require('request');
var data:any = [];
data[5] = {email5 : "abc#gmail.com"};
request.post({
"url": "https://api.jotform.com/form/formId/submissions?apiKey=apikey",
"json": {
submission : data
},
"headers": {
"Content-type": "application/json"
}
}, (error:any, response:any) => {
if (error) {
console.log(error);
}
else {
if(response){
console.log(response);
console.log('=================');
}
}
});
I'm getting an error of questionId.
Here is my error
body:
{ responseCode: 500,
message: 'error',
content: 'QuestionID not found on form questions!',
duration: '29ms' } }
Please help me!
NestJS API App use HttpService to call Another API and It works when no custom interceptor is used.
The HttpService API call is executed but it is not reached to another API and could not see the response.
This is get call code
get(path: string, body: any = {}): Observable<AxiosResponse<any>> {
console.log('DomainAPI Response Begining');
const url = this.baseURL + path;
this.updateLastUtilizedTimestamp();
return this.httpService.get(url, { validateStatus: null }).pipe(
tap(data => {
console.log('DomainAPI Response Tap', data);
}),
retryWhen(
this.rxJSUtilsService.genericRetryStrategy({
numberOfAttempts: 3,
delayTime: 200,
ignoredErrorCodes: [500],
}),
),
catchError(this.formatErrors),
);
}
if any custom interceptor is used, I found the following when debug.
arguments:TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
The Postman shows the following response.
{
"statusCode": 500,
"message": {
"Title": "TypeError",
"Type": "Error",
"Detail": "Converting circular structure to JSON\n --> starting at object with constructor 'Observable'\n | property 'operator' -> object with constructor 'CatchOperator'\n --- property 'caught' closes the circle",
"Status": "Status",
"Extension": ""
},
"timestamp": "Exception - AllExceptionsFilter 2019-12-26T17:29:42.447Z"
}
I changed the above as below but still it is not working
get(path: string, body: any = {}) {
console.log('DomainAPI Response Begining');
const url = this.baseURL + path;
this.updateLastUtilizedTimestamp();
return this.httpService.get(url, { validateStatus: null }).pipe(
map(response => {
console.log('DomainAPI Response Tap', response.data);
return response.data;
}),
);
}
It gives the following response in the postman
{
"data": {
"_isScalar": false,
"source": {
"_isScalar": false,
"source": {
"_isScalar": false
},
"operator": {}
},
"operator": {}
}
}
Please advise
async get(path: string, body: any = {}): Promise<any> {
...
const res = await this.httpService.get(url, { validateStatus: null }).toPromise();
return res.data;
}
get(path: string, body: any = {}) {
...
return this.httpService.get(url, { validateStatus: null })
.toPromise()
.then(res => res.data)
.catch(err => this.logger.error(err));
}
Converting to a promise using the .toPromise() method has been deprecated because we are working with observables and a promise returns only one value while observables could return no value or more that one value (see more #: Conversion to Promises). So as an example using the question above the solution would be:
import { lastValueFrom } from 'rxjs';
get(path: string, body: any = {}): Observable<AxiosResponse<any>> {
console.log('DomainAPI Response Begining');
const url = this.baseURL + path;
this.updateLastUtilizedTimestamp();
return await lastValueFrom(
this.httpService.get(url, { validateStatus: null })
.pipe(
tap(data => {
console.log('DomainAPI Response Tap', data);
}),
retryWhen(
this.rxJSUtilsService.genericRetryStrategy({
numberOfAttempts: 3,
delayTime: 200,
ignoredErrorCodes: [500],
}),
),
catchError(this.formatErrors),
));
}
Basically all you have to do is wrap the whole http request with firstValueFrom or lastValueFrom, in this case lastValueFrom is what would be appropriate. Visit the link to the documentation on Conversion to promises above by rxjs to know more about this.
NOTE: I added just the lastValueFrom import only as a clear indicator of what is needed.
This is another example using my own code:
async send_otp(
phone: string,
channel: string,
): Promise<Observable<AxiosResponse<any>>> {
return await lastValueFrom(
this.httpService
.post(`/messaging/otp/`, {
sender: 'Oyinkayy',
destination: '234' + String(phone).slice(1),
length: 6,
channel: channel,
reference: '',
})
.pipe(
tap((resp) => console.log(resp)),
map((resp) => {
return resp.data;
}),
tap((data) => console.log(data)),
catchError(async (err) => {
return err;
}),
),
);
}
[ { hostname: 'www.google.com',
path: '/recaptcha/api/siteverify',
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Content-Length': 556 } },
'{"secret":"XXXUseThisForCommunicationBetweenYourSiteAndGoogleXXX","response":"03AHJ_VuusXdr5IdGpNzQPRjedGs-Le066Fx9r-Lk1gIfLqlzwxapPx70_LukmcOsw3x-m2DSfpvQVylx060H9IjFP82fy7505_t_rjSivauiwBUyQPrBMp5kTRviq_DD1L2mVMTTrBieUMlQM69AIuG3KwmdOQMyMJS2iJdRuRNnvAmDlPSejkASR4X-7c4IIP3NoMb52Qsl9QPeU6kGaPtxqmf1IpNwbSC3bzLXQD-QV1aI4GgaeqSPfOO8EPfISJMQ5kbCd9wqAwHqDAXMtNSvz10Ty30R71HqmsSk7YHddFQhei1L6y9j7nxnY5QtAxHehhpYwJVNjI96hxeIaG58_CQHGbAufy4aPGAlf-zJ6be_Xtdzd4AnHxiX9OuCKQI8eQlh6DZLGaymxXDmPNu4TijGyyu0VeTPTTKf12zVUg86_0ZmszWZDtALjnNnxBH7bZqrgWXhy","remoteip":"00.00.000.000"}' ]
If I post that and google returns this:
{ success: false, 'error-codes': [ 'missing-input-response', 'missing-input-secret'] }
I don't see what is happening wrong
https://www.google.com/recaptcha/admin#site/XXXXXX?setup says:
When your users submit the form where you integrated reCAPTCHA, you'll get as part of the payload a string with the name "g-recaptcha-response". In order to check whether Google has verified that user, send a POST request with these parameters:
URL: https://www.google.com/recaptcha/api/siteverify
secret(required) - XXXXXX,
response(required) - The value of 'g-recaptcha-response',
remoteip - The end user's ip address.
I have clearly sent all these things! What could be happening here? The error does not say they are wrong, it says they are 'missing'
And the above Quoted text from google clearly says POST not GET Google reCAPTCHA: how to get user response and validate in the server side
But if I try a GET request then the response is [ null, 400, undefined ]
UPDATE
As #mscdex pointed out application/x-www-form-urlencoded is required but the responce still said that it was missing the secret so I url encoded this instead as I figured something bad may be happening to the item at the start of the object.
{'_':'_','secret':'XXXXXX','response':'whateverXXYsgTSG','remoteip':'00.00.000.000'}
And finally it worked:
[ { hostname: 'www.google.com',
path: '/recaptcha/api/siteverify?',
method: 'POST',
headers:
{ 'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': 548 } },
'"_=_&secret=XXXXXX&response=03AHJ_VuurQFgsftybLlvrdGOwXfNneWp4v7FPJJbOD9CGpiHAkFBaiNy7YWXcHrAkU6SPU5UZpgKCptU3gRX5OPqXEh2qqP3nXJpiBWoxFW_Iv05P2UA23rzzZk0ecScmMSL1PP1uyBCdJ08HpAWEuz2PzL6m6u71k09xQbVbPZ5KT6qnb-mdPNyEkdBxtc9a5oYpnOoHg7ax6q4Ms4Lis4qrNBLCavKmYZ6vAmYitSEI0a0GERnlI3wLSvayhc-Yygv1koKIjg2q8GHXV1UhKLzBa8t8x2ibRBNwXUMBFs3Qj_lfwgiTNtIaU3kEAFPULJulZDOsAcovKpjk5xkyMM2C5YDGYMioeyOMl9ZmyyvkwfrrRe8e9o_tD6SaTTSAcrcxsfYGm-w0_CDbsa2IWSkjiMN-2B9SClOZJGXXVXVIuIYClIK3XuUvTsObCzxJAq2IKwwMTtYX&remoteip=00.00.000.000"' ]
[ { success: true }, 200, undefined ]
But I would like to do this properly not hacky So if anyone can answer how to do it properly that would be swell!
var JSON={
https:require('https')
, toquery:require('../node_modules/querystring').stringify
, stringify:require('../node_modules/json-stringify-safe')
, parse:require('../node_modules/try-json-parse')
, get:function(url,callback){process.env.NODE_TLS_REJECT_UNAUTHORIZED="0";var req=JSON.https.request(url,function(res){var buffer='';res.setEncoding('utf8');res.on('data',function(chunk){buffer+=chunk;});res.on('end',function(){try{var data=JSON.parse(buffer);callback(data,res.statusCode);}catch(e){console.log(e);}});});req.end();}
, post:function(url,path,data,type,callback){if(!callback){callback=type;type=undefined;}data=JSON.stringify(data);var options={hostname:url,path:path,method:'POST',headers:{'Content-Type':type||'application/json','Content-Length':data.length}};console.dir([options,data]);var req=JSON.https.request(options,function(res){var buffer='';res.setEncoding('utf8');res.on('data',function(chunk){buffer+=chunk;});res.on('end',function(){try{var data=JSON.parse(buffer);callback(data,res.statusCode);}catch(e){console.log(e);}});});req.write(data);req.end();}
};
JSON.post(
'www.google.com'
, '/recaptcha/api/siteverify?'
, JSON.toquery({'_':'_','secret':'XXXX','response':response,'remoteip':remoteip})
, 'application/x-www-form-urlencoded'
, function(data,result,statusCode){
console.dir([data,result,statusCode]);
if(result.success){}
else{}
});
Here is how I do it in one of my project using superagent. This is my recaptcha-helper.js
var request = require("superagent");
var config = {
recaptcha: {
secret: "XXXXX",
url: "https://www.google.com/recaptcha/api/siteverify",
},
};
var ERROR_CODES = {
"missing-input-secret": "Unexpected Server Error (1)",
"invalid-input-secret": "Unexpected Server Error (2)",
"missing-input-response": "Missing reCAPTCHA value",
"invalid-input-response": "Invalid reCATPCHA value",
};
exports.getErrorCode = function (errorCode) {
if (Array.isArray(errorCode)) {
var errors = errorCode.map(function (code) {
return exports.getErrorCode(code);
});
return errors.join("\n");
}
return ERROR_CODES[errorCode] ||
(errorCode ? ("Unexpected reCAPTCHA error: " + errorCode) : "Unexpected reCAPTCHA error");
};
exports.parseResponse = function (err, res) {
if (err) {
return { success: false, error: err };
} else if (!res.body.success) {
var error = new Error(exports.getErrorCode(res.body["error-codes"]));
return { success: false, error: error };
} else {
return { success: true };
}
};
exports.verify = function (response, ip) {
if (process.env.NODE_ENV === "test") {
return response ? Promise.resolve() :
Promise.reject(new Error("Test reCAPTCHA Error"));
}
return new Promise (function (resolve, reject) {
request.post(config.recaptcha.url)
.type("form")
.accept("json")
.send({
secret: config.recaptcha.secret,
response: response,
remoteip: ip,
})
.end(function (err, res) {
var parsedRes = exports.parseResponse(err, res);
return parsedRes.success ? resolve() : reject(parsedRes.error);
});
});
};
And you can use it doing
var captchaHelper = require('./recaptcha-helper');
captchaHelper.verify(req.body.captcha, req.ip)
.then(function () {
// on success
}).catch(function (err {
// on error
});
I solved this by passing secret and response as a query parameter:
Example :
axios.post("https://www.google.com/recaptcha/api/siteverify?secret="
+ 'XXXXXX' + "&response=" + response + "&remoteip=" + req.connection.remoteAddress);