I am translating my little website from express+handlebars to an express+sapper project.
I would like to catch server side errors (for instance, a voluntary error when you go to /api/error) and render them using the sapper _error.svelte template.
I tried just throwing the error without my custom handler, but it returns an ugly text page with only the error stack, and does not seem to be catched by sapper's error handler
so I added my own error handler, and I can render HTML (bare, with no css yet) but is there a way I could use the sapper _error.svelte template ?
// ----------------------- src/server.js
import sirv from 'sirv'
import express from 'express'
import compression from 'compression'
import * as sapper from '#sapper/server'
import fatal500 from './middlewares/fatal500'
const { PORT, NODE_ENV } = process.env
const dev = NODE_ENV === 'development'
const app = express()
app.use(compression({ threshold: 0 }))
app.use(sirv('static', { dev }))
// the voluntary error thrower --------------------------------
app.get('/api/error', (req, res, next) => {
const error = new Error('this is a voluntary error')
error.code = 'VOLUNTARY'
next(error)
})
app.use(sapper.middleware())
app.use(fatal500) // the custom error handler -----------
app.listen(PORT, err => {
if (err) console.log('error', err)
})
// ---------------------src/middlewares/fatal500.js
export default function fatal500 (err, req, res, next) {
if (err.code !== 'VOLUNTARY') console.error(err.stack)
try {
res.status(500)
.type('html')
.send(
'<h1>Oooops ... 500 server error</h1>' +
'<p>It seems the server has encountered an error,<br/>' +
' try to <a href=\'/\'> return to the website</a><br/>' +
' or to send me the stack' +
'</p>' +
'<h2>Error Stack :</h2>' +
'<pre class="code"><code>' +
err.stack +
'</code></pre>'
)
} catch (e) {
res.status(500)
.type('text')
.send(
'\n\n' +
'**************************************\n' +
'Ooops ... 500\n' +
'the server encountered an unhandled error,\n\n' +
'if it is not voluntary (going to /api/error)\n' +
'please EMAIL ME THE FOLLOWING STACK at\n' +
'mail#mail.mail\n' +
'**************************************\n\n' +
'ORIGINAL ERROR STACK ------------------\n\n' +
err.stack + '\n\n' +
'ERROR HANDLING STACK ------------------\n\n' +
e.stack
)
}
}
Javascript is notoriously difficult to catch all types of error in. Sapper doesn't have any explicit handling for these errors either, however there is a neat third party component which allows this.
The first way, which I personally use, is this library: https://www.npmjs.com/package/#crownframework/svelte-error-boundary
Which essentially will catch errors (within reason) at the boundary of a component. It provides a way to attach a function so that you can then do what you like with that error.
I'm currently in the process of building this into Svelte itself. You can feed back on the RFC https://github.com/sveltejs/rfcs/blob/rfc/error-boundary/text/0000-error-boundary.md
The way in which I use the boundary is that I attach the handler to sentry - https://sentry.io which will break down and diagnose issues for you, so that you can fix them. Take a look!
Related
I am making a cron job instance that is running using Node to run a job that removes posts from my Redis cache.
I want to promisify client.zrem for removing many posts from the cache to insure they are all removed but when running my code I get the error below on line: "client.zrem = util.promisify(client.zrem)"
"TypeError [ERR_INVALID_ARG_TYPE]: The "original" argument must be of type function. Received undefined"
I have another Node instance that runs this SAME CODE with no errors, and I have updated my NPM version to the latest version, according to a similar question for this SO article but I am still getting the error.
TypeError [ERR_INVALID_ARG_TYPE]: The "original" argument must be of type Function. Received type undefined
Any idea how I can fix this?
const Redis = require("redis")
const util = require(`util`)
const client = Redis.createClient({
url: process.env.REDIS,
})
client.zrem = util.promisify(client.zrem) // ERROR THROWN HERE
// DELETE ONE POST
const deletePost = async (deletedPost) => {
await client.zrem("posts", JSON.stringify(deletedPost))
}
// DELETES MANY POSTS
const deleteManyPosts = (postsToDelete) => {
postsToDelete.map(async (post) => {
await client.zrem("posts", JSON.stringify(post))
})
}
module.exports = { deletePost, deleteManyPosts }
Node Redis 4.x introduced several breaking changes. Adding support for Promises was one of those. Renaming the methods to be camel cased was another. Details can be found at in the README in the GitHub repo for Node Redis.
You need to simply delete the offending line and rename the calls to .zrem to .zRem.
I've also noticed that you aren't explicitly connecting to Redis after creating the client. You'll want to do that.
Try this:
const Redis = require("redis")
const client = Redis.createClient({
url: process.env.REDIS,
})
// CONNECT TO REDIS
// NOTE: this code assumes that the Node.js version supports top-level await
client.on('error', (err) => console.log('Redis Client Error', err));
await client.connect(); //
// DELETE ONE POST
const deletePost = async (deletedPost) => {
await client.zRem("posts", JSON.stringify(deletedPost))
}
// DELETES MANY POSTS
const deleteManyPosts = (postsToDelete) => {
postsToDelete.map(async (post) => {
await client.zRem("posts", JSON.stringify(post))
})
}
module.exports = { deletePost, deleteManyPosts }
Below is the piece of code for my route.patch function that I defined for /:productId
route.patch('/:productId',(req,res,next)=>{
const id = req.params.productId;
const updateOps = {};
console.log(req.body);
for (const ops of req.body) {
updateOps[ops.propName] = ops.value;
console.log(updateOps);
}
res.status(200).json({Message: 'Hi'});
});
console.log(req.body) before the for loop is working but the console.log(updateOps) inside for loop is not working. And the even the res.status(200).json({Message: 'Hi'}); is not working . I am getting a route not found error.
Basically everything before for loop is working and everything after for loop is not working.
Can you please let me know where am I doing wrong. Is it the way I use for loop inside route.patch is wrong? Any help is highly appreciated.
Thanks
Answering your question regarding the error-handling from the comments. You have the following middlewares:
app.use((req, res, next) => {
const error = new Error('Not found');
//console.log(error.status) //console.log(error.message)
error.status = 404; //console.log(error.message)
next(error);
});
app.use((error, req, res, next) => {
res.status(error.status || 500);
res.json({
error: {
message: 'Route not found'
}
})
});
So for every request an error-object will be created which you assign status 404 and pass it on to the next middleware. There you send the error response and since the status is already set to 404 this status is used.
Actually you should just remove the first middleware where you create the error, as this would be done for every request. Express already handles requests to routes that do not exist and will return a 404 not found response. You can keep the second middleware to handle any other unhandled errors though (you should change the error message though :))
How i can hide the errors in browser console?
I don't know how to hide these errors in the browser, i am using axios with vuejs
The code is
login(user){
let formData = new FormData();
formData.set('username', user.username);
formData.set('password', user.password);
return this._http
.post(`${baseUrl}/api/auth/login`, formData)
}
this._http -> is the axios service
You can catch your error this way:
export default {
errorCaptured(err, vm, info) {
// err: error trace
// vm: component in which error occured
// info: Vue specific error information such as lifecycle hooks, events etc.
// TODO: Perform any custom logic or log to server
// return false to stop the propagation of errors further to parent or global error
handler
}
}
My scenario is to automate three sections in the same page and each section has a radio button, drop down etc..
After filling all the fields in each section I need to click Continue button and it takes a while to load.
I have successfully completed automating two sections, but when I click Continue button in the second section to navigate to the third. I am facing the below error
"TypeError: doneDeferred.fulfill is not a function"
I have understood that it may be synchronisation issue.So, I used
browser.ignoreSynchronisation=true;
Also, i tried to use
await browser.sleep(30000).then(function() {
console.log('Hello');
});
because I thought that since its taking a while to load its not inputting the values.But strangely, it doesn't go inside the function and print the console log message.
and this is the code in the debugger.js file:
validatePortAvailability_(port) {
if (this.debuggerValidated_) {
return selenium_webdriver_1.promise.when(false);
}
let doneDeferred = selenium_webdriver_1.promise.defer();
// Resolve doneDeferred if port is available.
let tester = net.connect({ port: port }, () => {
doneDeferred.reject('Port ' + port + ' is already in use. Please
specify ' +
'another port to debug.');
});
tester.once('error', (err) => {
if (err.code === 'ECONNREFUSED') {
tester
.once('close', () => {
doneDeferred.fulfill(true);
})
.end();
}
else {
doneDeferred.reject('Unexpected failure testing for port ' +
port + ': ' + JSON.stringify(err));
}
});
return doneDeferred.promise.then((firstTime) => {
this.debuggerValidated_ = true;
return firstTime;
}, (err) => {
console.error(err);
return process.exit(1);
});
Expected:I have pass values through sendkeys and drop down in that section and click continue button.
Actual:Its hanging in that screen and getting the above error.
I believe that the issue is with selenium webdriver promises.Can anyone help me with this?
I am still in the learning face with protractor cucumber framework.
Here is the background of the question : I'm following the kick-off-koa using Koa 2. But the exercises in the kick-off are designed for Koa 1. I've created an issue for this problem of Koa 2 : Task of error handler with Koa 2 cannot pass.
For short, my problem is how to display a custom error page when a 500 error happens.
Here are the codes :
// error handler middleware
function errorHandler(ctx, next) {
try {
return next();
}
catch(err) {
ctx.status = err.status || 500;
// I would like to display the custom message as follows
ctx.body = 'Oops! internal server error';
// with emitting the error event, don't work
// ctx.app.emit('error', err, ctx);
}
}
// to generate error
app.use(router.get('/error', ctx => {
ctx.throw('oops', 500);
}));
But my page of error is always displaying as "Internal Server Error", which is the default message. It seems that ctx.body = 'Oops! internal server error'; couldn't modify the page.
Thanks for the helps!
If you are using Koa2, you don't have to return inside middleware, instead, use await. And by the way, your middleware function MUST be an async function.
Here is an example of a combined 404 and 500 middleware:
app.use(async (ctx, next) => {
try {
await next()
if (ctx.status === 404) ctx.throw(404)
} catch (err) {
console.error(err)
ctx.status = err.status || 500
ctx.body = errorPage.render({ // Use your render method
error: err,
})
}
})
// Your normal routes here
First, Koa awaits for the next middleware in the chain (which is your normal routes). If nothing is found or an error occurred, the middleware chain goes backwards and the next line is executed, which throws a 404 and its captured inside the catch.
Now in the catch statement, you can get either 404, 500 (by default) or 5xx if other error occurred.
The body of the page is also set with a render of your template and passing the error to the template so you can make use of it.
You don't have to emit the error as this is the last catch in the chain.