graphql - pitfalls

    There are probably no perfect technologies. Graphql is no exception. If you have not had experience with this technology, then you need to have a good idea of ​​what problems you may have and prepare for them in advance.

    To begin with, I’ll say that I’m more a supporter than an adversary of using graphql around where possible. And I’m not going to dissuade anyone at all about the appropriateness of using this technology. And that is why I raise questions that relate to unresolved issues in the framework of graphql technology.

    For example, for someone it may be unexpected that each object in graphql will have to be described at least twice: once as the return type of the object, and once again as the input type of the object (seegraphql.org/graphql-js/mutations-and-input-types ). However, I told this to begin with and do not even consider it a significant drawback. Today we will focus on such issues that, as a rule, have to be solved when developing an application using graphql technology:

    1. Separation of access for users and user groups.
    2. Error processing.
    3. SELECT N + 1 Problem

    Separation of access for users and user groups


    graphql does not know anything about sharing access between users and groups. Thus, all the work of sharing access is the responsibility of the application developer. The third parameter passes the application context object to the resolver function. Therefore, if you, for example, work with the implementation of graphql JavaScript + express, then in the context parameter you can get the current user from the request express.js object. But further work on access control should be carried out directly in each resolver:

    function(root, {id}, ctx) {
       return DB.Lists.get(id)
         .then( list => {
           if(list.owner_id && list.owner_id != ctx.userId){
             throw new Error("Not authorized to see this list");
           } else {
             return list;
           }
        });
    }
    

    Naturally, this approach complicates access control because there is no way to set access rights in a declarative manner, and control of rights is dispersed over dozens (for some large systems, over thousands) of resolver functions. Therefore, there are a number of libraries that solve this problem. Some of them are quite popular (judging by the number of stars on github.com), for example github.com/maticzav/graphql-shield .

    Error processing


    If your frontend requires input validation and the formation of detailed messages for each field that has not passed validation, then error handling in graphql will most likely seem not flexible enough to you. For example, if the input parameter was described as a string, and a numerical value was received, then the error message will be of little use for this:

    {
      "errors": [
        {
          "message": "Expected type String, found 1.",
          "locations": [
            {
              "line": 2,
              "column": 15
            }
          ]
        }
      ]
    }
    

    If there is a gross error in the type of input parameter, then an error message will be generated automatically and there is no way to control this process. If validation by type of input parameter was successful, then it is possible to send a custom error message to the client by throwing the object new Error ('custom message ...'). You cannot add custom fields to the error object (error customization is implemented in the apollo-server-express and apollo-errors libraries when used together). Of course, it is always possible to serialize an object to a string messageon the server and deserialize on the client. But is it necessary to do so?

    SELECT N + 1 Problem


    This problem was discussed in detail in the message .

    graphql is built on resolver functions. This means that fetching data from the database can cause a problem called SELECT N + 1. Suppose that in the resolver function a list of objects was obtained in which the data associated with this object is represented by identifiers (foreign keys). For each such identifier, its own function resolver will be called, in which (in each) an additional request to the database will be made. Thus, instead of a single database query (with SQL JOIN), many queries will be executed, which overloads the database with queries.

    To solve this problem, facebook developed the github.com/graphql/dataloader librarythat uses a pending request strategy. Instead of executing the request directly in the function resolver, it is proposed to accumulate identifiers (secondary keys) in the array, and then receive them immediately with one request.

    apapacy@gmail.com
    May 13, 2019

    Also popular now: