2017-08-21 2 views
0

Ich bin auf eine Kuriosität in dem, was zurückgegeben wird, wenn ich ähnliche Mutationen ausführen. Ich lerne gerade diesen Stapel, und ich implementiere Mongodb mit Mungo als meine Datenbank-Ebene.Graphql Apollo React: Kann nicht Null für nicht Nullable zurückgeben

Ich habe zwei einfache Mutationen. man erstellt einen Benutzer und fügt ihn dem Register Datenbank aka hinzu. der andere fügt offensichtlich ein Profilbild hinzu, nachdem das anfängliche Benutzerobjekt erstellt wurde.

beide Resolver geben das vollständige Benutzerobjekt zurück, was für die Aktualisierung der Benutzerschnittstelle, des Speichers usw. hilfreich ist. Ich plane die Implementierung von Subskriptionen, daher ist es wichtig, dass ich die neuen Daten zurückbekomme.

ich arbeitete mit graphiql aus und rannte in ein seltsames Problem. Mein Update-Resolver gab null zurück, obwohl die Image-URL in der Datenbank gespeichert wurde. Der Register-Resolver gab alle Benutzerfelder zurück.

Bei der Konsolenprotokollierung der Rückgabeobjekte in den Resolvern gaben beide Funktionen ein vollständiges Benutzerobjekt zurück.

Wenn ich versuchte, das Rückgabeobjekt nicht nullbar zu machen, würde ich den Fehler erhalten kann nicht Null für nicht Nullable für den Update-Resolver zurückgeben.

mein Resolver verwendete anfänglich findOneAndUpdate mit einem Callback, der tatsächlich das Benutzerobjekt zurückgab. und ja, ich wurde immer noch null. seltsam.

ich änderte meinen Resolver zu einem eher manuellen Ansatz. Ich suche den bestehenden Benutzer mit findOne übergeben in der Benutzer-ID, dann explizit sagen user.profilePic = "url of pic" und das aufrufende Speichern des gesamten Benutzerobjekts und die Rückgabe des Benutzerobjekts im Callback zu diesem. und Boom, das funktioniert!

Was verursacht das also? Ich habe das anfängliche Gefühl, dass dies etwas mit Timing zu tun hat, irgendwie auch mit dem Warten auf den Callback .... ich verstehe wirklich nicht, warum meine erste Annäherung nicht funktioniert und meine zweite tut es. Ich werde den Code für beide vielleicht jemand mit einem tieferen Verständnis von Timing oder möglicherweise async Funktionen kann Chime in. Vielleicht muss ich meinen Stil von Callbacks zu versprechen oder async erwarten.

//this one doesnt work  
addProfilePic: (root, { input }, context) => { 
    let update = { profilePic: input.profilePic }; 
    let query = { id: input.id }; 
    let options = { new: true, upsert: true}; 
    let callback = ((err, user) => { 
    if(err) console.log(err.message); 
    return user; 
    }) 
    return updatedUser = User.findOneAndUpdate(query, update, options, callback) 
}      

//this one works, but returns old user object to client... 
//so really, no, it doesn't work 
addProfilePic: (root, { input }, context) => { 
    return User.findOne({id: input.id}, ((err,user) => { 
    if(err)console.log(err); 
    if(user){ 
     user.profilePic = input.profilePic; 
     user.save((err) => { 
     if(err)console.log(err); 
     console.log(user); 
     return user; 
     }) 
    } 
    }) 
}) 

Anmerkung: in Zusammenhang vorbei, wenn ich implementieren tatsächlich werde ich id aus dem Kontext erhalten, die den Benutzer enthält, wenn sie angemeldet sind . Anmerkung: diese sind bald coole Tools, aber viel zu lernen, vor allem für jemanden mit 3 Monaten Gesamtcodierung exp ... dh ich ...

Antwort

2

Trotz was die Dokumente sagen, wenn Sie einen Rückruf enthalten, findOneAndUpdate gibt zurück undefined. Auf der anderen Seite gibt findOne ein Abfrageobjekt zurück. Das Problem hier ist, wenn Sie einen Callback übergeben, die Absicht ist, dass Sie die Werte behandeln, die an Ihren Callback als Argumente übergeben werden, und sich nicht mit dem Rückgabewert des Calls befassen.

Mit GraphQL kann ein Resolver einen Wert oder eine Promise zurückgeben, der zu diesem Wert aufgelöst wird. Das Query-Objekt, das von findOne zurückgegeben wird, ist kein Versprechen, aber es ist "thenable" und in gewisser Weise "kommt ihr davon", die Dinge auf diese Weise zu tun. Ich vermute jedoch, wenn Sie sich ansehen, was tatsächlich von GraphQL zurückgegeben wird, werden Sie feststellen, dass es das ursprüngliche Benutzerobjekt und nicht das gespeicherte Benutzerobjekt zurückgibt.

Wie Sie vermutet, gibt es eine bessere Art und Weise :)

mongoose Um ein Versprechen zurückzukehren, müssen Sie:

  1. den Rückruf Tropfen insgesamt
  2. Anfügen .exec() bis zum Ende von Ihrem Anruf

Jetzt sieht Ihr Resolver so aus:

addProfilePic: (root, { input }, context) => { 
    let update = { profilePic: input.profilePic }; 
    let query = { id: input.id }; 
    let options = { new: true, upsert: true}; 
    return User.findOneAndUpdate(query, update, options).exec() 
} 

Ein paar zusätzliche Anmerkungen, die Sie auf dem richtigen Weg zu bekommen:

Sie werden bemerken, ich keinen Fehler in dem obigen Code Handhabung. Dies liegt daran, dass GraphQL diese Fehler tatsächlich für Sie abfängt und in die Antwort aufnimmt. Wenn Sie jedoch zusätzliche Fehlerinformationen bereitstellen möchten, oder obfuscate die Details, die an den Client zurückgegeben werden, können Sie an Ihren Anruf anhängen, Ihren Fehler darin ändern und dann zurückwerfen.

Nachdem Sie nun ein Versprechen sind Rückkehr, können Sie then() verwenden wenn Sie mit dem Abfrageergebnis arbeiten müssen, nur nicht vergessen, im Inneren den Wert zurück!

return User.findOneAndUpdate(query, update, options).exec() 
    .then(user => { 
    console.log(user) 
    // you could modify the object being handed to GraphQL here 
    return user // IF you use a then, make sure you return the value!! 
    }) 

Schließlich, wenn Sie Rückrufe am Ende tun verwenden, beachten Sie, dass im Gegensatz zu Versprechungen, die return-Anweisungen in ihnen nichts tun (zumindest nicht in diesem Fall). Da sie asynchron sind, gibt es keine Möglichkeit, die Werte, mit denen sie aufgerufen werden, zurück an Ihren Ursprungsaufruf zurückzugeben (nicht ohne alles in ein Promise einzupacken, und das ist ein Pfad, der nicht wirklich wert ist, wenn Sie bereits ein Versprechen erhalten haben).

+0

Sie haben Recht, ich erkannte, dass ich mein ursprüngliches findOne Benutzerobjekt zurückgab, obwohl graphiql die korrekten aktuellen Daten anzeigte. Ich mag dieses Muster auch für Fehler, es wird mühsam, wie ich es gemacht habe. Ich habe es schwer gefunden, Standardmuster für diesen Stapel zu finden. sehr hilfreicher Rat. – benjaminadk

+0

@benjaminadk [Dies ist eine kuratierte Liste von GraphQL-Beispielen] (https://github.com/chentsulin/awesome-graphql). Da ist ein Paar, das Mungo benutzt, das du vielleicht hilfreich findest. –

Verwandte Themen