Attach request.url to any errors being logged, using hapi - error-handling

I am trying to add the requested path to all (or most, where it makes sense) server errors logged by NodeJS, the idea being that when viewing the logs in (insert tool of choice here) I'd be able to directly correlate NodeJS errors to the request.url.
I've been reading through the documentation for hapi but I haven't yet stumbled across a way to do this, partially because I am still wrapping my head around the request/response lifecycle and the best place to interject this logic. I tried something in my base controller class by adding request.url as error.url, but did not seem to get the results I was hoping for. I think what I need is an error event handler to attach this extra error property to, similar to restify's server.on('restifyError'), is there anything similar in hapi?

In the hapi docs it shows there are various events you can listen to like you would do like your Restify example. If you see this link it shows the names of events you can listen to.

I've gotten the following to do what I want, although it only seems to work for 500 errors so far.
server.on('request-error', function (request, err) {
console.log('Error response (500) sent for request: ' +
request.id + ', at: ' + request.url.path + ', because: ' +
(err.trace || err.stack || err));
});

Related

Multiple routers in Express Node.js

How can I display my data from mongoDB that have collections?
When I want to display they apart, its word but not when I try to reach them all together.
For example:
My index.js:
app.use('/menu', menuController);
My menuController.js:
router.use('/morning', morningController);
router.use('/starters', startersController);
router.use('/sandwiches', sandwichesController);
router.use('/toasts', toastsController);
router.use('/kidsMeal', kidsMealController);
router.use('/salats', salatsController);
router.use('/italianCuisine', italianCuisineController);
router.use('/mains', mainsController);
router.use('/stirFried', stirFriedController);
router.use('/desserts', dessertsController);
router.use('/softDrinks', softDrinksController);
router.use('/refreshing', refreshingController);
router.use('/hotBeverages', hotBeveragesController);
router.use('/warming', warmingController);
router.use('/various', variousController);
when I reach " http://localhost:2121/menu/morning"
I'm seeing my data in JSON from my Database (even when in get '/variousController').
But when I trying to get ' http://localhost:2121/menu', I'm getting an arrow ' Cannot GET /menu'.
What I'm doing wrong?
< But when I trying to get ' http://localhost:2121/menu', I'm getting an arrow ' Cannot GET /menu'. What I'm doing wrong?
You don't have any router in your router for "/" so the URL /menu all by itself has no route handler.
If you want /menu to have a handler, then define one:
router.get('/', someHandler); // to serve /menu
FYI, is there a reason you're using router.use() instead of an http-verb-specific variety such as router.get() for your endpoint handlers? router.use() matches all verbs including GET, POST, PUT, OPTIONS, etc... which is generally not what you want for an endpoint handler. An endpoint handler should only match the verb it is designed for.

Getting RapidAPI to work with GoogleSheets to extract IMDB data

Google Sheets with RapidAPI
First time trying to get APIs to work! I thought a simple project would be to get a Googlesheet to retrieve movie information based on the title.
Googling around I happened upon RapidAPI which has a Googlesheets add-on. Unfortunately I haven't found much useful documentation so have hit a dead end.
What I've learned so far
There only seems to be one example for how to implement it... by using the =GET() command like so (in this case for pulling finance info):
=GET(”https://investors-exchange-iex-trading.p.rapidapi.com/stock/{symbol}/book”,”quote.companyName”,”YOUR_API_KEY_HERE”,”symbol”,”AAPL”)
I couldn't get this example to work, and the IMDB Code Snippet seems a little different, so I'm not sure how that works at all. Not the curly bracers around {symbol}.
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://imdb8.p.rapidapi.com/title/find',
params: {q: 'Dredd'},
headers: {
'x-rapidapi-host': 'imdb8.p.rapidapi.com',
'x-rapidapi-key': '5840855726msh193dee7e1600046p145eddjsnc66aff778896'
}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
When I run a typical search on IMDB, I get a URL that looks like this:
https://www.imdb.com/find?q=dredd&ref_=nv_sr_sm
I notice this q parameter there, which seems important...
I'm not sure how I am meant to format this =GET() command for IMDB data. The example suggests one thing, but Googlesheets suggests another: "GET(url, selectPaths, rapidApiKey)"
I'm not sure what the curly bracers are doing in the example URL.
Whatever I try seems to give the same error message:
Error
Request failed for https://imdb8.p.rapidapi.com returned code 400. Truncated server response: 400 - Bad Request (use muteHttpExceptions option to examine full response) (line 98).
Send Help
Does anyone have a better, working tutorial for using this setup? Or could you direct me to some useful reading material that a layperson could understand?
I found a good resource for you. Check out this well-written article on RapidAPI's official blog.
https://rapidapi.com/blog/api-google-sheets/

How to use the AddAuthparameter procedure?

I have to add an authorization to a REST request in Delphi.
Can someone give me an example how should it call the AddAuthParameter procedure?
I am doing this code in an onclick event of a button :
authjo, auth1, auth2, auth3, auth4, auth5, auth6, auth7, auth8, auth9, auth10 : string;
authjo := auth1 + auth2 + auth3 + auth4 + auth5 + auth6 + auth7 + auth8 + auth9 + auth10 ;
Restrequest4.AddAuthParameter('Authorization',authjo,TRESTRequestParameterKind.pkHTTPHEADER);
Restrequest4.Execute;
But this does not use thes the Authorization token 'authjo' and i don't know why.
I must have Authorization like this "Authorization Bearer :token" am i not constructing well in the code ?
If the authentication expects a Bearer token, you must add that to your call:
Restrequest4.AddAuthParameter('Authorization','Bearer ' + authjo,TRESTRequestParameterKind.pkHTTPHEADER);
Having messed around with Delphi to access an API (In my case Trakt), I managed to authenticate with OAuth2. But I ran into the very same problem as you did.
I have just asked my question here:
Accessing TRAKT API from Delphi - issues with Bearer authentication [SOLVED]
As I understand it, the root cause it that adding headers like we do, will create a parameter entry that is "Authorize=Bearer [token]" whereas it should be "Authorize:Bearer [token]".
See here:
How to add a "Authorization=Bearer" header with Indy in Delphi?
I have managed to mitigate the issue and would like to reference to that thread.
Also, the tool Fiddler was most helpful to see what my app actually sent and what it got back.

CSRF failure in custom mongoose pre-hook (Keystone.js)

using keystone LocalFile type to handle image uploads. similar to the Cloudinary autoCleanup option, I want to be able to delete the uploaded file itself, in addition to the corresponding mongo entry when deleting entries through the admin ui.
in this case, I want to delete an "Album", and it's corresponding album cover.
Album.schema.pre('remove', function(next){
var path = this._original.album_cover.path + "/" + this._original.album_cover.filename
fs.unlink(path, function () {
console.log('deleted');
})
I get "CSRF failure" when using the fs module. I thought all CSRF protection was handled internally with Keystone.
Anyone know of a better solution to this?
Took a 10 minute break and came back and it seems to be working now. I also found this, which seems to be the explanation.
"Moreover double check your session timeout. In my dev settings the session duration is set to 3 minutes. So, if I end up editing something for more than that time, Keystone will return a CSRF error on save because the new session (generate in the meantime) invalidates the old token."
https://github.com/keystonejs/keystone/issues/1330

AngularJS resource service with jsonp fails

I'm trying to fetch the JSON output of a rest api in AngularJS. Here are the problems I'm facing:
The Rest api url has the port number in it which is being interpolated by AngularJS for a variable. I tried several resolutions for this in vain.
I'm having issues with JSONP method. Rest api isn't hosted on the same domain/server and hence a simple get isn't working.
The parameters to the rest api are slash separated and not like a HTML query string. One of the parameters is an email address and I'm thinking the '#' symbol is causing some problem as well. I wasn't able to fix this either.
My rest api looks something like: http://myserver.com:8888/dosomething/me#mydomain.com/arg2.
Sample code / documentation would be really helpful.
I struggled a lot with this problem, so hopefully this will help someone in the future :)
JSONP expects a function callback, a common mistake is to call a URL that returns JSON and you get a Uncaught SyntaxError: Unexpected token : error. Instead, JSONP should return something like this (don't get hung up on the function name in the example):
angular.callbacks._0({"id":4,"name":"Joe"})
The documentation tells you to pass JSON_CALLBACK on the URL for a reason. That will get replaced with the callback function name to handle the return. Each JSONP request is assigned a callback function, so if you do multiple requests they may be handled by angular.callbacks._1, angular.callbacks._2 and so forth.
With that in mind, your request should be something like this:
var url = 'http://myserver.com:8888/dosomething/me#mydomain.com/arg2';
$http.jsonp(url + '?callback=JSON_CALLBACK')
.then(function (response) {
$scope.mydata = response.data;
...
Then AngularJS will actually request (replacing JSON_CALLBACK):
http://myserver.com:8888/dosomething/me#mydomain.com/arg2?callback=angular.callbacks._0
Some frameworks have support for JSONP, but if your api doesn't do it automatically, you can get the callback name from the querystring to encapsulate the json.
Example is in Node.js:
var request = require('request');
var express = require('express');
var app = express();
app.get('/', function(req, res){
// do something to get the json
var json = '{"id":4,"name":"Joe"}';
res.writeHead(200, {"Content-Type": "application/javascript"});
res.write(req.query.callback + '(' + json + ')');
res.end();
});
app.listen(8888);
The main issue I was facing here was related to CORS. I got the $http to retrieve the JSON data from the server by disabling the web security in Chrome - using the --disable-web-security flag while launching Chrome.
Regarding the 8888 port, see if this works:
$scope.url = 'http://myserver.com:port/dosomething/:email/:arg2';
$scope.data = $resource($scope.url, {port:":8888", email:'me#mydomain.com',
arg2: '...', other defaults here}, …)
Try escaping the ':'
var url = 'http://myserver.com\:8888/dosomething/me#mydomain.com/arg2';
Pretty sure I read about this somewhere else