Reputation: 2283
I wanted to implement a rudimentary leaderboard to my game on Repl.it, so I created a node.js backend. This is what I have on the backend:
const express = require('express');
const Client = require('@replit/database');
const db = new Client();
const cors = require('cors');
const bcrypt = require('bcrypt');
const bodyParser = require('body-parser');
const server = express();
server.use(cors());
server.use(bodyParser.json());
server.use(bodyParser.urlencoded({ extended: false }));
server.get('/', (req, res) => {
res.send('Online');
});
server.post('/leaderboard', async (req, res) => {
const m = await db.get('leaderboard');
m.push({
score: parseInt(req.body.score, 10),
time: new Date()
});
m.sort((a, b) => b.score - a.score);
await db.set('leaderboard', m);
res.send(req.body);
});
server.get('/leaderboard', async (req, res) => {
const leaderboard = await db.get('leaderboard');
res.json(leaderboard);
});
server.listen(3000);
But whenever I try to POST, I get the following error:
(node:344) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'push' of null
(node:344) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag
--unhandled-rejections=strict
(see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:344) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
And if I try to GET, res
returns null
- probably since I'm not pushing anything when doing POST.
Why is this happening, and how do I fix it?
Upvotes: 0
Views: 440
Reputation: 135357
How to handle the promise rejection?
You're getting the UnhandledPromiseRejectionWarning because you have nothing to catch the errors happening in your asynchronous routes. See the express error handling guide. You need to attach some kind of error handler -
var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(bodyParser.json())
app.use(...)
// error handler
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
app.post(...)
app.get(...)
...
Calls to next()
and next(err)
indicate that the current handler is complete and in what state. next(err)
will skip all remaining handlers in the chain except for those that are set up to handle errors...
Why is the promise rejected?
The error is happening because m
is null
and null
does not have a .push
method. Calling null.push(...)
throws an error which causes the promise to be rejected with this error.
Why does m
have a null
value?
I don't know the repl.it API, but presumably there is no value for db.get('leaderboard')
and that is why m
is getting a null
response. You could try fixing it like this
server.get('/leaderboard', async (req, res) => {
const leaderboard = (await db.get('leaderboard')) || [] // <-
res.json(leaderboard);
});
server.post('/leaderboard', async (req, res) => {
const m = (await db.get('leaderboard')) || [] // <-
// ...
});
Adding ... || []
to the result says if the response of db.get
is falsey (null
is falsey), use the empty array, []
, instead.
replit/database
set(key: string, value: any): promise<void>
get(key: string): promise<any | null>
get(key: string, {raw: true}): promise<string | null>
set automatically encodes the value using JSON.stringify
.
get is designed to retrieve JSON strings and automatically decode them. If no string is found, a null
value returned, which is what your were experiencing.
Note, you can use db.get(someKey, {raw: true})
to get the raw string back, skipping the JSON.parse
step.
Upvotes: 1