Как получить доступ к окончательному GraphQL-Reponse в nest.js с помощью перехватчика - PullRequest
3 голосов
/ 08 июля 2019

Я реализовал LoggingInterceptor, который должен иметь доступ к окончательному Ответу GraphQL с его свойствами данных и ошибок + исходное тело запроса и аутентифицированный пользователь, который был добавлен к запросу до AuthGuard. (РЕДАКТИРОВАТЬ: Частично разрешается с помощью @ jay-mcdoniel: user и body доступны через GqlExecutionContext.create(context).getContext())

Действительно, Перехватчик предоставляет только один полностью разрешенный GraphQL-объект.

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(tap(
      (allData) => console.log(allData),
      (error)=> console.log(error)));
  }
}

Это мой класс перехватчиков.Это просто вызов RxJS-оператора tap для регистрации текущих значений наблюдаемой.

Если я запускаю следующий GraphQL-запрос ...

mutation {
  login(data: { username: "admin", password: "123456" }) {
    id
    username
    token
  }
}

... мой серверправильно отвечает следующим телом ответа:

{
  "data": {
    "login": {
      "id": "6f40be3b-cda9-4e6d-97ce-ced3787e9974",
      "username": "admin",
      "token": "someToken"
    }
  }
}

Но содержимое allData, которое регистрируется в консоли моим перехватчиком, выглядит следующим образом:

{
  id: '6f40be3b-cda9-4e6d-97ce-ced3787e9974',
  isAdmin: true,
  username: 'admin',
  firstname: null,
  lastname: null,
  email: null,
  created: 2019-07-05T15:11:31.606Z,
  token: 'someToken'
}

Вместо этого я хотел бычтобы увидеть информацию о реальном теле ответа.

Я дополнительно попытался получить доступ к HttpResponse по context.switchToHttp().getResponse().Но он содержит только параметры метода мутации-входа в систему:

{
  data: [Object: null prototype] { username: 'admin', password: '123456' }
}

РЕДАКТИРОВАТЬ :

console.log(GqlExecutionContext.create(context).getContext()); отпечатков (все еще нет GraphQL-ResponseBody):

{
  headers: {
    /*...*/
  },
  user: /*...*/,
  body: {
    operationName: null,
    variables: {},
    query: 'mutation {\n  login(data: {username: "admin", password: ' +
      '"123456"}) {\n    token\n    id\n    username\n    isAdmin\n  }\n' +
      '}\n'
  },
  res: ServerResponse {
    _events: [Object: null prototype] { finish: [Function: bound resOnFinish] },
    _eventsCount: 1,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    _last: false,
    chunkedEncoding: false,
    shouldKeepAlive: true,
    useChunkedEncodingByDefault: true,
    sendDate: true,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: null,
    _hasBody: true,
    _trailer: '',
    finished: false,
    _headerSent: false,
    socket: Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: null,
      _readableState: [ReadableState],
      readable: true,
      _events: [Object],
      _eventsCount: 8,
      _maxListeners: undefined,
      _writableState: [WritableState],
      writable: true,
      allowHalfOpen: true,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: [Server],
      _server: [Server],
      timeout: 120000,
      parser: [HTTPParser],
      on: [Function: socketOnWrap],
      _paused: false,
      _httpMessage: [Circular],
      [Symbol(asyncId)]: 566,
      [Symbol(kHandle)]: [TCP],
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: Timeout {
        /*...*/
      },
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0
    },
    connection: Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: null,
      _readableState: [ReadableState],
      readable: true,
      _events: [Object],
      _eventsCount: 8,
      _maxListeners: undefined,
      _writableState: [WritableState],
      writable: true,
      allowHalfOpen: true,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: [Server],
      _server: [Server],
      timeout: 120000,
      parser: [HTTPParser],
      on: [Function: socketOnWrap],
      _paused: false,
      _httpMessage: [Circular],
      [Symbol(asyncId)]: 566,
      [Symbol(kHandle)]: [TCP],
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: Timeout {
        _idleTimeout: 120000,
        _idlePrev: [TimersList],
        _idleNext: [TimersList],
        _idleStart: 3273,
        _onTimeout: [Function: bound ],
        _timerArgs: undefined,
        _repeat: null,
        _destroyed: false,
        [Symbol(refed)]: false,
        [Symbol(asyncId)]: 567,
        [Symbol(triggerId)]: 566
      },
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0
    },
    _header: null,
    _onPendingData: [Function: bound updateOutgoingData],
    _sent100: false,
    _expect_continue: false,
    req: IncomingMessage {
      /*...*/
    },
    locals: [Object: null prototype] {},
    [Symbol(isCorked)]: false,
    [Symbol(outHeadersKey)]: [Object: null prototype] {
      'x-powered-by': [Array],
      'access-control-allow-origin': [Array]
    }
  },
  _extensionStack: GraphQLExtensionStack { extensions: [ [CacheControlExtension] ] }
}

1 Ответ

3 голосов
/ 08 июля 2019

Перехватчик фактически вызывается до и после ответа, или он должен быть как минимум, чтобы вы могли иметь логику перед запросом (запрос на вход) и логику после запроса (ответ на выход).Вы должны быть в состоянии выполнить всю предварительную обработку запроса до того, как позвоните по номеру next.hanlde(), а затем сможете использовать RxJS Observable operators, например tap или map после вызова pipe().Ваша переменная allData должна содержать всю информацию из запроса / ответа, и вы даже можете использовать переменную context для получения еще большей информации.

Что сейчас печатает allData для вас?Вы пробовали GqlExecutionContext.create(context).getContext().req или GqlExecutionContext.create(context).getContext().res?Они показаны в документации Guards для получения объектов запроса и ответа, как при обычном вызове HTTP.

...