J'essaie (Apollo) GraphQL côté serveur et j'ai eu un problème probablement stupide. J'essaie d'inscrire un utilisateur, mais je reçois toujours l'erreur indiquée dans l'image liée ci-dessous. Quel est le problème? Ignorez le flux d'authentification très simple, car je ne fais que tester le GraphQl
Voici les extraits de code pertinents:
Schéma
export default `
type User {
id: ID!
name: String!
email: String!
}
type Query {
allUsers: [User]
currentUser: User
}
type Mutation {
createAccount(name: String!, email: String!, password: String!): User
loginUser(email: String!, password: String!): User
updatePassword(email: String!, password: String!, newPassword: String!): User
deleteAccount(email: String!, password: String!): User
}
`
Résolveurs
createAccount: async (
parent,
{ name, email, password },
{ User },
info
) => {
try {
// Check for invalid (undefined) credentials
if (!name || !email || !password) {
return 'Please provide valid credentials';
}
// Check if there is a user with the same email
const foundUser = await User.findOne({ email });
if (foundUser) {
return 'Email is already in use';
}
// If no user with email create a new user
const hashedPassword = await bcrypt.hash(password, 10);
await User.insert({ name, email, password: hashedPassword });
const savedUser = await User.findOne({ email });
return savedUser;
} catch (error) {
return error.message;
}
},
Le plus gros problème avec votre résolveur est que dans n'importe quel nombre de scénarios, au lieu de renvoyer un objet User
, vous retournez une chaîne. Votre schéma spécifie que createAccount
peut renvoyer un User
ou null
(si c'était User!
, il ne serait pas nullable, puis null
ne serait pas non plus un type valide).
Lorsque vous renvoyez une chaîne dans votre résolveur, car il attend un objet, il le contraint en un, puis commence à rechercher les propriétés User
sur cet objet (comme name
et email
). Ces propriétés n'existent pas, et comme il s'agit de propriétés non nulles sur votre objet User
, renvoyer null/undefined pour elles entraîne une erreur.
Votre résolveur devrait probablement lancer toutes les erreurs qu'il doit lancer. Ensuite, ils seront renvoyés dans le cadre du tableau errors
dans votre réponse. Par exemple:
// Check if there is a user with the same email
const foundUser = await User.findOne({ email })
if (foundUser) throw new Error('Email is already in use')
// If no user with email create a new user
const hashedPassword = await bcrypt.hash(password, 10);
await User.insert({ name, email, password: hashedPassword });
const savedUser = await User.findOne({ email });
return savedUser;
Maintenant, si vous avez un e-mail en double, la réponse ressemblera à ceci:
{
"data": {
"createAccount": null
},
"errors": [
{
"message": "Email is already in use",
"locations": [
{
"line": 4,
"column": 3
}
],
"path": [
"createAccount"
]
}
]
}
Si vous souhaitez manipuler la façon dont vos erreurs sont affichées sur le client, vous devez utiliser les options de configuration formatError
ou formatResponse
pour votre middleware de serveur Apollo. Il est également recommandé d'utiliser des erreurs personnalisées, ce qui vous permet d'ajouter des propriétés personnalisées comme code
pour identifier plus facilement le type d'erreur du côté client.
Enfin, il n'est pas nécessaire de vérifier si le nom, l'e-mail ou le mot de passe sont définis dans votre résolveur - votre schéma a déjà ces entrées marquées comme non nulles, ce qui signifie que GraphQL renverra automatiquement une erreur si l'une d'entre elles est manquante.