Skip to content

Instantly share code, notes, and snippets.

@Sowed
Last active May 5, 2020 05:53
Show Gist options
  • Save Sowed/246614abb27f71f668b6e9a314ae6acd to your computer and use it in GitHub Desktop.
Save Sowed/246614abb27f71f668b6e9a314ae6acd to your computer and use it in GitHub Desktop.
Migrating from Custom Express Server with `express-validator` to Next API Routes
import express, { Request, Response, NextFunction } from 'express';
import { check, validationResult, ValidationChain } from 'express-validator';
import bodyParser from 'body-parser';
import next from 'next';
const postMail = async (req: Request, res: Response): Promise<void> => {
// Use nodemailer to post the email. Setup mailer() with nodemailer
// and call it to Post an Email and return response
const mailResponse = await mailer(req.body);
res.json(mailResponse);
};
const postValidationRules = (): ValidationChain[] => {
return [check('email').isEmail(), check('message').escape()];
};
const validate = (
req: Request,
res: Response,
nextFn: NextFunction
): Response<string> | void => {
const errors = validationResult(req);
if (errors.isEmpty()) {
return nextFn();
}
return res.status(422).json({
errors,
});
};
const port = parseInt(process.env.PORT || '3000', 10);
const clientUrl = process.env.CLIENT_URL || 'http://localhost';
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
(async (): Promise<void> => {
try {
await app.prepare().then(() => {
const server = express();
server.use(bodyParser.json());
server.use(bodyParser.urlencoded({ extended: true }));
server.post(
'/api/post-contact-form',
postValidationRules(),
validate,
postMail
);
server.get('*', (req: Request, res: Response) => {
return handle(req, res);
});
server.post('*', (req: Request, res: Response) => {
return handle(req, res);
});
server.listen(port, (error: Error) => {
if (error) throw error;
console.info(`> ✔ Ready on Server: ${clientUrl}:${port}`);
});
});
} catch (error) {
console.error(`❌ Error`, error);
process.exit(1);
}
})();
@hoangvvo
Copy link

hoangvvo commented May 5, 2020

const resolvedPromises = await Promise.all(promises).catch(e => console.log(e))
// log out that one error among the promises.

If you prefer to returns all the error in your resolvedPromises:

const promises = postValidationRules().map(midd => runMiddleware(req, res, midd).catch(e => e)) // Catch and return the error

const resolvedPromises = await Promise.all(promises) // this won't reject.

resolvedPromises should contain all the errors.

@Sowed
Copy link
Author

Sowed commented May 5, 2020

I have created a repro and you can test it out here.

I left some inline-comments based on your previous recommendations and removed the input fields for brevity, created two separate form data formats for comparison, expecting the invalid one to fail. However both pass and return the final should be sanitized and emailed data.

I am currently looking into running the validation in an imperative way using run()
but the approach is too repetitive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment