Entering and Modifying Data via GraphQL

Running createOrder Mutation

🙋 Need help? Ask an expert now!

createOrder Mutation

Load the QUERY VARIABLES section of your GraphiQL browser window with this content from doc/graphql-grahiql-samples.md, Mutations, Create Order, Variables:

{
  "order_data_input": {
    "order_data": {
      "user_id": "VXNlcjoxRTRZbzExWTNyOWE=",
      "payer_id": "VXNlcjoxRTRZbzExWTNyOWE=",
      "order_date": "2018-09-10T00:00:00.000Z",
      "order_items": [
        {
          "item_id": "SXRlbToxSEVPeDZGbkM3Y00=",
          "quantity": 5,
          "amount": 10.13,
          "item_details": "{\"packaging\": \"frozen-pack\", \"special_handling\": {\"before_shipping\": \"freeze\", \"in_transit\":\"refrigerate\"}}"
        },
        {
          "item_id": "SXRlbToxR1ZsMjFscTBTOHA=",
          "quantity": 2,
          "amount": 15.99,
          "item_details": "{\"color\": \"black\"}"
        }
      ]
    }
  }
}

Note that if you already have user_data_input variable in your GraphiQL, add a comma after its JSON block and remove the closing and opening curly bracket in between the user_data_input and order_data_input - to have your Query Variables section look as a single JSON object with two variables in it.

The mutation code in GraphiQL is as follows (copy it from doc/graphql-grahiql-samples.md as well):

mutation sendOrder($order_data_input: CreateOrderInput!) {
  createOrder(input: $order_data_input) {
    order_id
    completionObj {
      code
      msg_id
      msg
      processed
      modified
    }
  }
}

In the demo project, no duplicate validation is coded on the User Order content, so this mutation can be run multiple times with the same data - new identical Documents will be created.

Mutation Schema

The src/relay-mutations/order/create-order-mutation.js contains the Input Object definition.

mutateAndGetPayload reorganizes the input and converts Global IDs into those used in the database:

  mutateAndGetPayload: (inputFields, viewer, info) => {
    logger.debug(`in mutateAndGetPayload Create Order `);
    logger.debug(`  inputFields ` + JSON.stringify(inputFields));
    const orderObj = {
      order_date: inputFields.order_data.order_date,
      order_items: []
    };
    orderObj.user_id = fromGlobalId(inputFields.order_data.user_id).id;
    orderObj.payer_id = fromGlobalId(inputFields.order_data.payer_id).id;
    for (let item of inputFields.order_data.order_items) {
      const itemObj = { ...item };
      itemObj.item_id = fromGlobalId(item.item_id).id;
      orderObj.order_items.push(itemObj);
    }
    return createOrder(orderObj, viewer);
  }

Notice, how orderObj is declared as a const and initialized with 2 parameters: order_date and an empty order_items array. Then two more parameters are added to it using the dot notation: orderObj.user_id and orderObj.payer_id. The Items array is populated in the for loop over the corresponding input data.

Mutate-and-Get Function and The Database Processor

"Mutate and Get" function createOrder is in src/relay-mutate-and-get/order-mag.js:

  • converts the item_details strings into JS objects via JSON.parse(). The conversion is placed into try/catch as this would generally be a place where problems with the inbound data format may break the application. In the demo code, the process exits on the first error. A common production-quality system would scan all records and report errors for the entire set at the end, if any
  • calls OrderCud.createOrder

Database function createOrder is in src/db-handlers/order/order-cud.js.

Order ID Validation Loop and MongoDB Error Checking

Similarly to createUser, the Order ID is generated via id_gen(). However, in this flow we don't validate the uniqueness of the ID by querying the database. Instead, the while loop is coded wrapping the create method execution on the UserOrder model. If the ID is not unique, the create will error out with a message like this:

MongoError: E11000 duplicate key error collection: web_dev.user_order index: _id_ dup key: { : "1UtNnZBYUHDx" }

mongoose documentation recommends using this check when trapping unique index violation errors:

err.message.indexOf('duplicate key error') !== -1

Sounds great. If the documentation suggests this as the official approach, vs., e.g., somehow extracting the error code, etc. - we're using it. The only problem, if we have multiple unique indexes in the Collection we need to make sure the problem is with the _id field - that we can fix by re-generating - vs. with another field that we should report back to the client as a hard stop error.

As MongoDB reports the troubled key back - we can compare it with the _id, so the final error trapping condition is

  if (
        err.message.indexOf(order_id) !== -1 &&
        err.message.indexOf('duplicate key error') !== -1
      )



As the last mutation topic - let's see what happens when we combine several ones together. Who would guess it's totally possible in GraphQL (on the client side)

Edit Me on GitHub!