Currently, I am in the process of honing my error-handling skills within Express while using a Postgres database.
My backend code consists of numerous small functions that serve as intermediaries for handling interactions with the database in larger functions.
When it comes to sending requests, should I validate the type beforehand or simply send the request and handle any errors returned by the database?
I find myself repeatedly writing similar sections of code, which feels like a poor coding pattern. Unfortunately, I haven't been able to locate a definitive answer to this dilemma online.
// Approach #1: Type-checking before executing query
export const getPerson = ({
emailAddress,
personID,
}: {
emailAddress?: string;
personID?: string;
}) => {
// Custom BadRequestError is thrown if input types are incorrect
if (!isString(emailAddress)) throw new BadRequestError();
if (!isUUID(personID)) throw new BadRequestError();
return pool
.query(
`SELECT
*
FROM person
WHERE ($1::citext IS NULL OR person.emailAddress = $1)
AND ($2::uuid IS NULL OR person.person_id = $2)`,
[emailAddress, personID]
)
.then((res) => res.rows)
.catch(() => { throw new InternalServerError(); })
};
// Approach #2: No type checking prior to executing query, handling error based on response
// This method may seem cleaner but can result in losing information about invalid inputs
// It also sends a bad request directly to the database
export const getPerson = ({
emailAddress,
personID,
}: {
emailAddress?: string;
personID?: string;
}) => pool
.query(
`SELECT
*
FROM person
WHERE ($1::citext IS NULL OR person.emailAddress = $1)
AND ($2::uuid IS NULL OR person.person_id = $2)`,
[emailAddress, personID]
)
.then((res) => res.rows)
.catch((e) => {
switch (e.code) {
case '23XXX':
throw new BadRequestError();
}
}
);
In most scenarios, would you recommend sticking with approach #1 or #2? Are there other common practices worth considering?