Do we need to wrap app.get in async function - javascript

I've come across this code
(async () => {
app.get('/health', (req: Request, res: Response) => {
res.send();
});
more endpoints here
....
})();
I don't get why we need to wrap app.get in async here, is that necessary?

Probably not, but we'd need more context to be sure. As shown, no, there's no point.
It may be that they were relying on information they only got asynchronously for setting up the routes and wanted to use await rather than .then/.catch when using that information, e.g.:
(async () => {
try {
app.get('/health', (req: Request, res: Response) => {
res.send();
});
const moreRoutes = await getMoreRoutes();
// −−−−−−−−−−−−−−−−^^^^^
for (const route of moreRoutes) {
// ...set up more routes
}
} catch (e) {
// Handle/report error
}
})();
If so, hopefully they have a try/catch around the entire body (as shown above) or a .catch at the end like this:
(async () => {
app.get('/health', (req: Request, res: Response) => {
res.send();
});
const moreRoutes = await getMoreRoutes();
// −−−−−−−−−−−−−−−−^^^^^
for (const route of moreRoutes) {
// ...set up more routes
}
})().catch(e => {
// Handle/report error
});
async/await can make it much easier (IMHO) to read code. But the above can be done with .then/.catch as well:
app.get('/health', (req: Request, res: Response) => {
res.send();
});
getMoreRoutes()
.then(moreRoutes => {
// ...set up more routes
})
.catch(e => {
// Handle/report error
});

Related

Using async await on .then function with parameters

I'm doing some functional testing with mocha. I stored my functions name, parameters and sucess message in local JSON file. I am checking my database response with local JSON response.
I'm using .then and .catch everywhere. I am looking to clean up a code with async await. How I can use async await here?
it('Check Authentication', (done) => {
readFileData('checkAuth').then(({ params, message}) => {
login.checkAuth({ ...params })
.then((result) => {
assert(result.message === message);
done();
})
.catch((err) => done(err));
});
});
Something like this. Haven't tested it tho. Basically instead of .then() you just await the call. Note that there is async before (done) callback. .catch() can be caught with try/catch block.
it('Check Authentication', async (done) => {
let response = await readFileData('checkAuth');
try {
let message = await login.checkAuth({ ...response.params }); // or w/e the response is
// assert the message
} catch (e) {
// do something with the error
}
});
Changed callback function to async to use `await
Wrapped all await calls in try-catch block to handle errors
Used const for params, message and result variables but if you are going to reassign values later in the code you can use let instead.
done() will be async call. Add await in front of that if you need that too to be sync call
it('Check Authentication', async (done) => {
try {
const { params, message } = await readFileData('checkAuth');
const result = await login.checkAuth({ ...params });
assert(result.message === message);
done();
} catch (err) {
done(err);
}
});

Jest testing async function - Jest did not exit one second after the test run has completed

I want to test my Next.js API functions with Jest using node-mocks-http.
This is the function I want to test:
export default async (
req: NextApiRequest,
res: NextApiResponse
): Promise<void> => {
const foods = await getFoods()
res.json(foods)
}
This is how my test file looks like:
import { createMocks } from 'node-mocks-http'
import handler from './foods'
test('api route', async (done) => {
try{
const { req, res } = createMocks({
method: 'GET',
})
await handler(req, res)
expect(res._getStatusCode()).toBe(200)
done()
} catch(err){
done(err)
}
})
Without the await getFoods() call everything works as expected. However with the call I get the Error: Jest did not exit one second after the test run has completed. The getFoods() is an async prisma database query.
What is missing here?
Don't mix done() and async code also, you don't need the catch block, the test will fail if the async function rejects.
import { createMocks } from 'node-mocks-http'
import handler from './foods'
test('api route', async () => {
const { req, res } = createMocks({
method: 'GET',
})
await handler(req, res)
expect(res._getStatusCode()).toBe(200)
})
It seems that you have synchronization problem so you should check https://jestjs.io/es-ES/docs/25.x/tutorial-async and there is always the typical timer solution in case your handler function is not working correctly you can try something like this
test('api route', async (done) => {
try{
const { req, res } = createMocks({
method: 'GET',
})
await handler(req, res)
setTimeout(() => {
expect(res._getStatusCode()).toBe(200)
done()
}, 1000);
} catch(err){
done(err)
}
})
This warning disappears if I add this to my test file:
afterAll(async () => {
await prisma.$disconnect()
})

Passing res wrapped in object into callback fails

I have a temporary server that looks like this:
import http from 'http'
export default function tempServer(
port: number
): Promise<{ req: http.IncomingMessage; res: http.ServerResponse }> {
return new Promise((resolve) => {
const server = http
.createServer(function (req, res) {
resolve({ req, res })
// This works
// res.write('Hey!')
// res.end()
server.close()
})
.listen(port)
})
}
And I am trying to manipulate res by calling res.write in another function:
function () {
const server = tempServer(parseInt(process.env.AUTH_PORT) || 5671)
return server.then(({req, res}) => {
const data = url.parse(req.url, true).query
...
res.write('Error: ' + data.error)
res.end()
...
})
}
The result is that res.write and res.write have no effect. I am sure the issue has something to do with contexts and bindings but I am having trouble going about it. Anyone willing to indulge me?

Redis Javascript Async Function

I have an array of Id' and i need to get the details for each of them.
i currently have this.
const redis = require('redis');
const redisClient = redis.createClient(process.env.REDIS_PORT, process.env.REDIS_HOST);
const arrayList = [
{ id: 3444 },
{ id: 3555 },
{ id: 543666 },
{ id: 12333 },
];
async function getDetails(element) {
await redisClient.hgetall(element.id, (err, user) => {
if (err) {
console.log('Something went wrong');
// Handle Error
return err;
}
console.log('Done for User');
return user;
});
}
arrayList.forEach((element) => {
console.log('element');
await getDetails(element).then((res) => {
// Do Something with response for each element
});
});
This is the response i get right now. its not async. What am i doing wrong please.
element
element
element
element
Done for User
Done for User
Done for User
Done for User
So how things go on in async/await is, you create an async function and inside that function you await for other operations to finish. You call that async function without await OR you wrap it(func call) inside another async function.
arrayList.forEach((element) => {
console.log('element');
let returnedPromise= getDetails(element);
console.log("Promise after getDetails function", returnedPromise);
});
This code change should resolve the error.
Array.forEach() does not wait for promises to execute before moving to the next item.
You could instead use a for-loop in an async function, like so:
async function main() {
for (const element of arrayList) {
const response = await getDetails(element);
// do something with reponse for each element
}
}
main()
.then(() => /* on success */)
.catch((err) => /* on error */);

How to perform a callback in a promise?

I have here a function which gets a Section. It returns a Promise
router.get('/menu_section', (req, res) => {
Section.read(req.body)
.then(d => {
send(d, res);
})
.catch(e => {
error(e, res);
});
});
Is there a way, that while I handle the Promise I can cut down on the then catch boilerplate code? I am looking to write it in this way to reduce boiler plate.
router.get('/menu_section', (req, res) => {
Section.read(req.body).respond(data, err, res)
});
//handle it in this way for all routes.
function respond(data, err, res){
if(err) res.data({err})
else res.json({data});
}
EDIT: I want to avoid writing then catch altogether for every Promise handle
You wouldn't be able to do exactly what you mentioned (without overriding Promise, which is generally frowned upon).
You could however create a simple wrapping function to do it for you:
function respond(promise, res) {
promise
.then(data) => res.data(data))
.catch(err => res.data({err})
}
router.get('/menu_section', (req, res) => {
respond(Section.read(req.body), res);
});
You could even boil this down a bit to something like this:
function respond(getData) {
return (req, res) => {
getData(req)
.then(data) => res.data(data))
.catch(err => res.data({err})
};
}
router.get('/menu_section', respond(req => Section.read(req.body)));
With the second approach, you're basically just providing a function which gets the data, then it'll take that and process it in a standard way. It'll also create a function for taking req and res itself.
Maybe with currying?:
const respond = res => data => {
res.json(data);
};
So you can do:
router.get('/menu_section', (req, res) => {
Section.read(req.body).catch(e => e).then(respond(res));
});
However then i would directly make a middleware out of it:
const respond = (req, res, next) => {
Section.read(req.body).then(
data => res.json(data),
err => next(err)
);
};
So you can do
router.get('/menu_section', respond);
Note that async / await can be helpful here:
router.get('/menu_section', async (req, res) => {
try {
res.json(await Section.read(req.body));
} catch(e) {
res.json(e);
}
});
If you're looking to respond to all routes in this manner, you could use a Middleware function and use it application wide.
app.use((req, res, next) => (
Section.read(req.body)
.then(d => send(d, res))
.catch(e => error(e, res));
)
You can also use such function on a per-route basis, or even per-file (containing multiple routes).

Categories

Resources