Entering and Modifying Data via GraphQL

createUser Database Operation

🙋 Need help? Ask an expert now!

createUser MongoDB Call

src/db-handlers/user/user-cud.js createUser contains the mongoose code inserting the Document.

_id Generation and Validation

Notice, we generate the _id directly in the code so that we can easily return the ID back to the client:

...
import { id_gen } from '../../utils/url-id-generator';
...
  const user_id = id_gen();
...

id_gen() has been discussed in the "Mongo DB Datastore" chapter. createUser pre-validates that the generated _id is unique by querying the User Collection inside the while loop. Although, while (true) is a recipe for an infinite loop, the practicality of breaking out of this loop is guaranteed.

Once the uniqueness of the generated _id is confirmed - we optimistically assume that in the very short moment between the validation query run and the following User Document Create, exact the same ID would not be generated by the randomized id_gen() again. In "Running createOrder Mutation" lesson we will see how id_gen() is used in combination with MongoDB error checking as an alternative for pre-validation query.

Error Reporting

src/db-handlers/user/user-cud.js createUser returns errors back to src/relay-mutate-and-get/user-mag.js createUser as a rejected Promise. See inside the catch blocks:

...
  return Promise.reject('Error creating User');
...
  return Promise.reject('Error creating User', err);
...

In query processing, we used throw new Error(). The end effect is the same, so it is more of a coding style/standard decision which approach to use.

The important part is that unlike in queries where we let the GraphQL engine to wrap errors and send its own standard error object to the client, in the mutation process we block errors from flowing into the GraphQL engine. All logic in the "Mutate-and-Get" function src/relay-mutate-and-get/user-mag.js createUser is inside a try/catch block, and the catch section does not re-throw the error. Instead, it returns the same completionObj as in the error-free flow, except the content of the object is formed to inform the client that the process failed and provide enough details on the reason:

  catch (error) {
    return {
      completionObj: {
        code: '1',
        msg_id: 'EU01',
        msg: error.message,
        processed: 0,
        modified: 0
      }
    };
  }

On the receiving end, the client should always review the process result reported in the completionObj.

Logically, query errors are exceptions, whereas mutation errors can be caused by client-supplied data issues or business process flow gaps. Errors should be reported in a well-organized way, and the client's side logic should be coded to mitigate errors that can be fixed.

Controversially, GraphQL does not support setting specific HTTP response status codes like REST does. The codes are set by the engine that forms the HTTP response, and unless something terrible happened, the code is always 200 OK. The engine has to be customized if sending popular codes, those in the 4xx or 5xx series is a requirement. E.g., if the viewer validation fails, 401 Unauthorized is commonly expected on the client side, or 403 Forbidden if the query asks for something that the viewer has no access to. Can't do that with GraphQL. Some consider this being a limitation of GraphQL, and it is for traditionalists who used to checking the code before getting to the content of the response.


So, everything is pretty simple so far. Next, we'll look at a more substantial mutation operation - createOrder

Edit Me on GitHub!