Как включить информацию из директив схемы в качестве возвращаемых данных, используя Apollo Server 2.0 GraphQL? - PullRequest
1 голос
/ 29 марта 2019

Я использую директивы схемы для авторизации на полях.Сервер Apollo вызывает директивы после возвращения распознавателей.Из-за этого директивы не имеют доступа к выходным данным, поэтому, когда авторизация не проходит, я не могу включить соответствующую информацию для пользователя без извилистых обходных ошибок, которые всегда возвращают данные об ошибках независимо от того, запрашивает их запрос или нет.

Я надеюсь, что кто-то понимает внутренности Apollo лучше, чем я, и может указать, куда я могу вставить правильную информацию из директив, чтобы мне не пришлось нарушать стандартную функциональность GraphQL.

Я попытался включить мой вывод в контекст, но это не работает, несмотря на то, что директива имеет доступ, так как данные уже были возвращены из средств распознавания, и версия контекста после этого не нужна.

По состоянию напрямо сейчас я добавляю пользовательскую ошибку в директиву с кодом DIRECTIVE_ERROR и включаю сообщение, которое я хочу вернуть пользователю.В функции formatResponse я ищу директивные ошибки и фильтрую массив ошибок, передавая их в массив внутренних ошибок данных.Я знаю, что formatResponse не предназначен для изменения содержимого данных, но, насколько я знаю, это единственное место, где я могу получить доступ к тому, что мне нужно.Также расстраивает то, что объекты ошибок в ответе не включают все поля из ошибки.

type User implements Node {
  id: ID!
  email: String @requireRole(requires: "error")
}

type UserError implements Error {
  path: [String!]!
  message: String!
}

type UserPayload implements Payload {
  isSuccess: Boolean!
  errors: [UserError]
  data: User
}

type UserOutput implements Output {
  isSuccess: Boolean!
  payload: [UserPayload]
}

/**
 * All output responses should be of format:
 * {
 *  isSuccess: Boolean
 *  payload: {
 *    isSuccess: Boolean
 *    errors: {
 *      path: [String]
 *      message: String
 *    }
 *    data: [{Any}]
 *  }
 * }
 */
const formatResponse = response => {
  if (response.errors) {
    response.errors = response.errors.filter(error => {
      // if error is from a directive, extract into errors
      if (error.extensions.code === "DIRECTIVE_ERROR") {
        const path = error.path;
        const resolverKey = path[0];
        const payloadIndex = path[2];

        // protect from null
        if (response.data[resolverKey] == null) {
          response.data[resolverKey] = {
            isSuccess: false,
            payload: [{ isSuccess: false, errors: [], data: null }]
          };
        } else if (
          response.data[resolverKey].payload[payloadIndex].errors == null
        ) {
          response.data[resolverKey].payload[payloadIndex].errors = [];
        }

        // push error into data errors array
        response.data[resolverKey].payload[payloadIndex].errors.push({
          path: [path[path.length - 1]],
          message: error.message,
          __typename: "DirectiveError"
        });
      } else {
        return error;
      }
    });

    if (response.errors.length === 0) {
      return { data: response.data };
    }
  }

  return response;
};

Мое понимание порядка операций в Apollo таково:

преобразователи возвращают данные
данные отфильтрованы на основе параметров запроса?
директивы вызываются для объекта / поля, к которому применены
данные отфильтрованы на основе параметров запроса?
formatResponse имеет возможность изменять выходные данные
formatError имеет возможность изменятьошибки
возврат к клиенту

Мне бы хотелось, чтобы не приходилось выдавать ошибки в директивах, чтобы создать информацию для передачи пользователю путем ее извлечения в formatResponse.Ожидаемый результат для клиента - получить только те поля, которые он запрашивает, но текущий метод разбивает его и возвращает ошибки данных и все поля независимо от того, запрашивает ли их клиент.

...