typescript - Hoe implementeer je een Sveltekit Post-endpoint dat een asynchrone database-aanvraag doet?
Dus wanneer ik toegang krijg tot de SvelteKit post-endpoint, werkt het prima als ik wat waarden verstuur en ze niet door de validatiecontroles komen. Het retourneert de juiste status en body. Echter, wanneer het de database-insert uitvoert, geeft de endpoint een 404-fout terug, maar wordt de gebruiker correct in de database ingevoerd. Ik neem aan dat dit komt omdat de database-aanroep asynchroon is en SvelteKit niet wacht op het resultaat om terug te keren, maar ik weet niet zeker hoe ik mijn code moet aanpassen zodat het wacht en de juiste JSON-respons verstuurt.
Bedankt voor alle hulp!
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
Ik eindigde met het gebruik van het pg-promise pakket in plaats van het pg pakket om mijn database te verbinden.
Hieronder staat de bijgewerkte code voor het geval iemand een soortgelijk probleem heeft.
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()
}
};
}
}
Antwoord #1
Je probleem is dat de database die je gebruikt is geïmplementeerd met een callback-systeem function query(queryString, callback) en jouw await er niet op wacht, noch is de return in de callback daadwerkelijk een return uit je endpoint.
Het beste wat je kunt doen, is controleren of je databaselibary een asynchrone methode heeft waar je zoiets of iets dergelijks kunt doen:
const { errror, result } = await db.query(....)
Op deze manier zal de applicatie daadwerkelijk wachten tot de query is voltooid.
