Home > Mobile >  How do you implement a Sveltekit Post endpoint which makes an async DB request?
How do you implement a Sveltekit Post endpoint which makes an async DB request?

Time:11-04

So when I access the SvelteKit post endpoint it works fine if I submit some values and they don't pass validation checks. It returns the correct status and body. However when it makes the DB insert, the endpoint returns a 404 error but it inserts the user into the DB ok. I assume it is because the DB call is asynchronous And SvelteKit is not waiting for the result to return, but not sure how to change my code so it waits and sends the correct json response.

Thanks for any help!

import type { EndpointOutput } from '@sveltejs/kit';
import bcrypt from 'bcrypt';
import { randomUUID } from 'crypto';
import db from '$lib/config/db.js';
import { roles } from '$lib/config/roles.js';
import validation from '$lib/_helpers/validation';

export async function post({
    body
}: {
    body: { firstName: string; lastName: string; emailAddress: string; password: string };
}): Promise<EndpointOutput> {
    //lets trim any whitespace on the fields
    console.log(body);
    const firstName = body?.firstName.trim();
    const lastName = body?.lastName.trim();
    const email = body?.emailAddress.trim();
    const password = body?.password.trim();
    const userRole = roles.web   roles.anonymous;
    const bcryptPassword = await bcrypt.hash(password, 10);
    const emailToken = randomUUID();
    // double check the validation on the fields in case user submits directly to this endpoint.
    if (validation.validateEmail(email) == false) {
        //console.log(email);
        return {
            status: 422,
            body: {
                message: 'Please enter a valid email address.'
            }
        };
    }
    if (validation.validatePassword(password) == false) {
        return {
            status: 422,
            body: {
                message: 'Password must be at least 6 characters.'
            }
        };
    }
    if (validation.validateNotEmpty(firstName) == false) {
        return {
            status: 422,
            body: {
                message: 'First Name is required.'
            }
        };
    }
    if (validation.validateDisplayName(lastName) == false) {
        return {
            status: 422,
            body: {
                message: 'Last Name is required.'
            }
        };
    }

//insert user
    await db.query(
        'INSERT INTO users (first_name, last_name, email, user_password, user_role, email_verification_token) VALUES ($1, $2, $3, $4, $5, $6)',
        [firstName, lastName, email, bcryptPassword, userRole, emailToken],
        (error, results) => {
            // console.log(error, results);
            if (error) {
                return {
                    status: 417,
                    body: {
                        message: error.toString()
                    }
                };
            }
            //console.log(results);
            return {
                status: 201,
                body: {
                    message: 'User created successfully'
                }
            };
        }
    );
}

UPDATE FIX

I ended up using the pg-promise package instead of the pg package to connect my db.

Below is the updated code in case someone has a similar issue.

import type { EndpointOutput } from '@sveltejs/kit';
import bcrypt from 'bcrypt';
import { randomUUID } from 'crypto';
import { roles } from '$lib/config/roles.js';
import validation from '$lib/_helpers/validation';
import { db } from '$lib/config/db.js';

export async function post({
    body
}: {
    body: { firstName: string; lastName: string; emailAddress: string; password: string };
}): Promise<EndpointOutput> {
    //lets trim any whitespace on the fields
    console.log(body);
    const firstName = body?.firstName.trim();
    const lastName = body?.lastName.trim();
    const email = body?.emailAddress.trim();
    const password = body?.password.trim();
    const userRole = roles.web   roles.anonymous;
    const bcryptPassword = await bcrypt.hash(password, 10);
    const emailToken = randomUUID();
    // double check the validation on the fields in case user submits directly to this endpoint.
    if (validation.validateEmail(email) == false) {
        //console.log(email);
        return {
            status: 422,
            body: {
                message: 'Please enter a valid email address.'
            }
        };
    }
    if (validation.validatePassword(password) == false) {
        return {
            status: 422,
            body: {
                message: 'Password must be at least 6 characters.'
            }
        };
    }
    if (validation.validateNotEmpty(firstName) == false) {
        return {
            status: 422,
            body: {
                message: 'First Name is required.'
            }
        };
    }
    if (validation.validateDisplayName(lastName) == false) {
        return {
            status: 422,
            body: {
                message: 'Last Name is required.'
            }
        };
    }

    //check if user already exists.
    const userAlreadyExists = await db.oneOrNone('SELECT email from users WHERE email=$1 LIMIT 1', [
        email
    ]);
    console.log(' result: '   userAlreadyExists);
    if (userAlreadyExists) {
        return {
            status: 409,
            body: {
                message: 'User with that email already exists'
            }
        };
    }

    try {
        // insert New user into DB
        await db.none(
            'INSERT INTO users (first_name, last_name, email, user_password, user_role, email_verification_token) VALUES ($1, $2, $3, $4, $5, $6)',
            [firstName, lastName, email, bcryptPassword, userRole, emailToken]
        );

        return {
            status: 201,
            body: {
                message: 'User created successfully'
            }
        };
    } catch (error) {
        return {
            status: 417,
            body: {
                message: error.toString()
            }
        };
    }
}

CodePudding user response:

Your problem is that the DB you are using is implemented with a callback system function query(queryString, callback) and your await doesn't wait for it, nor is the return in the callback actually a return out of your endpoint.

The best thing to do is to check if your database library has an async method where you can do something like this or similar:

const { errror, result } = await db.query(....)

This way the application will actually wait for the query to complete.

  • Related