1

I'm learning coding and NodeJS. One thing that I keep getting stuck on is trying to learn about the response object. It's massive and I'm not able to digest all the information I'm receiving when I console.log() or console.dir() it.

One tool that is really handy is the Chrome JSON viewer extender. Also this jsonviewer.stack.hu does the same thing by allowing you to post JSON objects and providing a readable view of the object.

Unfortunately it doesn't accept regular objects (as copied and pasted from my CLI). I've tried JSON.stringfy() on the object but this method strips 90% of the properties on the original object.

Is there an easy solution to viewing CLI logged object with the ability to collapse and expand the properties?

The object is logged in the CLI as follows:

    Response {
      _events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: undefined,
      res: IncomingMessage {
        _readableState: ReadableState {
          objectMode: false,
          highWaterMark: 16384,
          buffer: BufferList { head: null, tail: null, length: 0 },
          length: 0,
          pipes: null,
          pipesCount: 0,
          flowing: true,
          ended: true,
          endEmitted: true,
          reading: false,
          sync: true,
          needReadable: false,
          emittedReadable: false,
          readableListening: false,
          resumeScheduled: false,
          paused: false,
          emitClose: true,
          autoDestroy: false,
          destroyed: false,
          defaultEncoding: 'utf8',
          awaitDrain: 0,
          readingMore: true,
          decoder: [StringDecoder],
          encoding: 'utf8'
        },
        readable: false,
        _events: [Object: null prototype] {
          end: [Array],
          data: [Array],
          error: [Array],
          close: [Function: bound emit]
        },
        _eventsCount: 4,
        _maxListeners: undefined,
        socket: Socket {
          connecting: false,
          _hadError: false,
          _parent: null,
          _host: null,
          _readableState: [ReadableState],
          readable: true,
          _events: [Object: null prototype],
          _eventsCount: 6,
          _maxListeners: undefined,
          _writableState: [WritableState],
          writable: false,
          allowHalfOpen: false,
          _sockname: null,
          _pendingData: null,
          _pendingEncoding: '',
          server: null,
          _server: null,
          parser: null,
          _httpMessage: [ClientRequest],
          [Symbol(asyncId)]: 150,
          [Symbol(kHandle)]: [TCP],
          [Symbol(lastWriteQueueSize)]: 0,
          [Symbol(timeout)]: null,
          [Symbol(kBuffer)]: null,
          [Symbol(kBufferCb)]: null,
          [Symbol(kBufferGen)]: null,
          [Symbol(kBytesRead)]: 0,
          [Symbol(kBytesWritten)]: 0
        },
        connection: Socket {
          connecting: false,
          _hadError: false,
          _parent: null,
          _host: null,
          _readableState: [ReadableState],
          readable: true,
          _events: [Object: null prototype],
          _eventsCount: 6,
          _maxListeners: undefined,
          _writableState: [WritableState],
          writable: false,
          allowHalfOpen: false,
          _sockname: null,
          _pendingData: null,
          _pendingEncoding: '',
          server: null,
          _server: null,
          parser: null,
          _httpMessage: [ClientRequest],
          [Symbol(asyncId)]: 150,
          [Symbol(kHandle)]: [TCP],
          [Symbol(lastWriteQueueSize)]: 0,
          [Symbol(timeout)]: null,
          [Symbol(kBuffer)]: null,
          [Symbol(kBufferCb)]: null,
          [Symbol(kBufferGen)]: null,
          [Symbol(kBytesRead)]: 0,
          [Symbol(kBytesWritten)]: 0
        },
        httpVersionMajor: 1,
        httpVersionMinor: 1,
        httpVersion: '1.1',
        complete: true,
        headers: {
          'x-powered-by': 'Express',
          'set-cookie': [Array],
          location: '/',
          vary: 'Accept',
          'content-type': 'text/plain; charset=utf-8',
          'content-length': '23',
          date: 'Sat, 09 May 2020 09:52:40 GMT',
          connection: 'close'
        },
        rawHeaders: [
          'X-Powered-By',
          'Express',
          'Set-Cookie',
          'access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsInVzZXJpZCI6MSwiaWF0IjoxNTg5MDE3OTYwfQ.x4sRUhSqMaTFt2S3mrv6k3LOUecIgUJ4Cy8zWvdemss; Max-Age=3600; Path=/; Expires=Sat, 09 May 2020 10:52:40 GMT; HttpOnly',
          'Location',
          '/',
          'Vary',
          'Accept',
          'Content-Type',
          'text/plain; charset=utf-8',
          'Content-Length',
          '23',
          'Date',
          'Sat, 09 May 2020 09:52:40 GMT',
          'Connection',
          'close'
        ],
        trailers: {},
        rawTrailers: [],
        aborted: false,
        upgrade: false,
        url: '',
        method: null,
        statusCode: 302,
        statusMessage: 'Found',
        client: Socket {
          connecting: false,
          _hadError: false,
          _parent: null,
          _host: null,
          _readableState: [ReadableState],
          readable: true,
          _events: [Object: null prototype],
          _eventsCount: 6,
          _maxListeners: undefined,
          _writableState: [WritableState],
          writable: false,
          allowHalfOpen: false,
          _sockname: null,
          _pendingData: null,
          _pendingEncoding: '',
          server: null,
          _server: null,
          parser: null,
          _httpMessage: [ClientRequest],
          [Symbol(asyncId)]: 150,
          [Symbol(kHandle)]: [TCP],
          [Symbol(lastWriteQueueSize)]: 0,
          [Symbol(timeout)]: null,
          [Symbol(kBuffer)]: null,
          [Symbol(kBufferCb)]: null,
          [Symbol(kBufferGen)]: null,
          [Symbol(kBytesRead)]: 0,
          [Symbol(kBytesWritten)]: 0
        },
        _consuming: false,
        _dumped: false,
        req: ClientRequest {
          _events: [Object: null prototype],
          _eventsCount: 3,
          _maxListeners: undefined,
          outputData: [],
          outputSize: 0,
          writable: true,
          _last: true,
          chunkedEncoding: false,
          shouldKeepAlive: false,
          useChunkedEncodingByDefault: true,
          sendDate: false,
          _removedConnection: false,
          _removedContLen: false,
          _removedTE: false,
          _contentLength: 39,
          _hasBody: true,
          _trailer: '',
          finished: true,
          _headerSent: true,
          socket: [Socket],
          connection: [Socket],
          _header: 'POST /authenticate HTTP/1.1\r\n' +
            'Host: 127.0.0.1:41185\r\n' +
            'Accept-Encoding: gzip, deflate\r\n' +
            'User-Agent: node-superagent/3.8.3\r\n' +
            'Content-Type: application/json\r\n' +
            'Content-Length: 39\r\n' +
            'Connection: close\r\n' +
            '\r\n',
          _onPendingData: [Function: noopPendingOutput],
          agent: [Agent],
          socketPath: undefined,
          method: 'POST',
          path: '/authenticate',
          _ended: true,
          res: [Circular],
          aborted: false,
          timeoutCb: null,
          upgradeOrConnect: false,
          parser: null,
          maxHeadersCount: null,
          [Symbol(kNeedDrain)]: false,
          [Symbol(isCorked)]: false,
          [Symbol(kOutHeaders)]: [Object: null prototype]
        },
        text: 'Found. Redirecting to /'
      },
      request: Test {
        _events: [Object: null prototype] {},
        _eventsCount: 0,
        _maxListeners: undefined,
        _agent: false,
        _formData: null,
        method: 'POST',
        url: 'http://127.0.0.1:41185/authenticate',
        _header: {
          'user-agent': 'node-superagent/3.8.3',
          'content-type': 'application/json'
        },
        header: {
          'User-Agent': 'node-superagent/3.8.3',
          'Content-Type': 'application/json'
        },
        writable: true,
        _redirects: 1,
        _maxRedirects: 0,
        cookies: '',
        qs: {},
        _query: [],
        qsRaw: [],
        _redirectList: [],
        _streamRequest: false,
        _buffer: true,
        app: Server {
          _events: [Object: null prototype],
          _eventsCount: 2,
          _maxListeners: undefined,
          _connections: 0,
          _handle: null,
          _usingWorkers: false,
          _workers: [],
          _unref: false,
          allowHalfOpen: true,
          pauseOnConnect: false,
          httpAllowHalfOpen: false,
          timeout: 120000,
          keepAliveTimeout: 5000,
          maxHeadersCount: null,
          headersTimeout: 40000,
          _connectionKey: '6::::0',
          [Symbol(IncomingMessage)]: [Function: IncomingMessage],
          [Symbol(ServerResponse)]: [Function: ServerResponse],
          [Symbol(asyncId)]: 148
        },
        _asserts: [ [Function: bound ] ],
        _server: Server {
          _events: [Object: null prototype],
          _eventsCount: 2,
          _maxListeners: undefined,
          _connections: 0,
          _handle: null,
          _usingWorkers: false,
          _workers: [],
          _unref: false,
          allowHalfOpen: true,
          pauseOnConnect: false,
          httpAllowHalfOpen: false,
          timeout: 120000,
          keepAliveTimeout: 5000,
          maxHeadersCount: null,
          headersTimeout: 40000,
          _connectionKey: '6::::0',
          [Symbol(IncomingMessage)]: [Function: IncomingMessage],
          [Symbol(ServerResponse)]: [Function: ServerResponse],
          [Symbol(asyncId)]: 148
        },
        _data: { username: 'admin', password: 'admin' },
        req: ClientRequest {
          _events: [Object: null prototype],
          _eventsCount: 3,
          _maxListeners: undefined,
          outputData: [],
          outputSize: 0,
          writable: true,
          _last: true,
          chunkedEncoding: false,
          shouldKeepAlive: false,
          useChunkedEncodingByDefault: true,
          sendDate: false,
          _removedConnection: false,
          _removedContLen: false,
          _removedTE: false,
          _contentLength: 39,
          _hasBody: true,
          _trailer: '',
          finished: true,
          _headerSent: true,
          socket: [Socket],
          connection: [Socket],
          _header: 'POST /authenticate HTTP/1.1\r\n' +
            'Host: 127.0.0.1:41185\r\n' +
            'Accept-Encoding: gzip, deflate\r\n' +
            'User-Agent: node-superagent/3.8.3\r\n' +
            'Content-Type: application/json\r\n' +
            'Content-Length: 39\r\n' +
            'Connection: close\r\n' +
            '\r\n',
          _onPendingData: [Function: noopPendingOutput],
          agent: [Agent],
          socketPath: undefined,
          method: 'POST',
          path: '/authenticate',
          _ended: true,
          res: [IncomingMessage],
          aborted: false,
          timeoutCb: null,
          upgradeOrConnect: false,
          parser: null,
          maxHeadersCount: null,
          [Symbol(kNeedDrain)]: false,
          [Symbol(isCorked)]: false,
          [Symbol(kOutHeaders)]: [Object: null prototype]
        },
        protocol: 'http:',
        host: '127.0.0.1:41185',
        _endCalled: true,
        _callback: [Function],
        res: IncomingMessage {
          _readableState: [ReadableState],
          readable: false,
          _events: [Object: null prototype],
          _eventsCount: 4,
          _maxListeners: undefined,
          socket: [Socket],
          connection: [Socket],
          httpVersionMajor: 1,
          httpVersionMinor: 1,
          httpVersion: '1.1',
          complete: true,
          headers: [Object],
          rawHeaders: [Array],
          trailers: {},
          rawTrailers: [],
          aborted: false,
          upgrade: false,
          url: '',
          method: null,
          statusCode: 302,
          statusMessage: 'Found',
          client: [Socket],
          _consuming: false,
          _dumped: false,
          req: [ClientRequest],
          text: 'Found. Redirecting to /'
        },
        response: [Circular],
        called: true
      },
      req: ClientRequest {
        _events: [Object: null prototype] {
          drain: [Function],
          error: [Function],
          prefinish: [Function: requestOnPrefinish]
        },
        _eventsCount: 3,
        _maxListeners: undefined,
        outputData: [],
        outputSize: 0,
        writable: true,
        _last: true,
        chunkedEncoding: false,
        shouldKeepAlive: false,
        useChunkedEncodingByDefault: true,
        sendDate: false,
        _removedConnection: false,
        _removedContLen: false,
        _removedTE: false,
        _contentLength: 39,
        _hasBody: true,
        _trailer: '',
        finished: true,
        _headerSent: true,
        socket: Socket {
          connecting: false,
          _hadError: false,
          _parent: null,
          _host: null,
          _readableState: [ReadableState],
          readable: true,
          _events: [Object: null prototype],
          _eventsCount: 6,
          _maxListeners: undefined,
          _writableState: [WritableState],
          writable: false,
          allowHalfOpen: false,
          _sockname: null,
          _pendingData: null,
          _pendingEncoding: '',
          server: null,
          _server: null,
          parser: null,
          _httpMessage: [Circular],
          [Symbol(asyncId)]: 150,
          [Symbol(kHandle)]: [TCP],
          [Symbol(lastWriteQueueSize)]: 0,
          [Symbol(timeout)]: null,
          [Symbol(kBuffer)]: null,
          [Symbol(kBufferCb)]: null,
          [Symbol(kBufferGen)]: null,
          [Symbol(kBytesRead)]: 0,
          [Symbol(kBytesWritten)]: 0
        },
        connection: Socket {
          connecting: false,
          _hadError: false,
          _parent: null,
          _host: null,
          _readableState: [ReadableState],
          readable: true,
          _events: [Object: null prototype],
          _eventsCount: 6,
          _maxListeners: undefined,
          _writableState: [WritableState],
          writable: false,
          allowHalfOpen: false,
          _sockname: null,
          _pendingData: null,
          _pendingEncoding: '',
          server: null,
          _server: null,
          parser: null,
          _httpMessage: [Circular],
          [Symbol(asyncId)]: 150,
          [Symbol(kHandle)]: [TCP],
          [Symbol(lastWriteQueueSize)]: 0,
          [Symbol(timeout)]: null,
          [Symbol(kBuffer)]: null,
          [Symbol(kBufferCb)]: null,
          [Symbol(kBufferGen)]: null,
          [Symbol(kBytesRead)]: 0,
          [Symbol(kBytesWritten)]: 0
        },
        _header: 'POST /authenticate HTTP/1.1\r\n' +
          'Host: 127.0.0.1:41185\r\n' +
          'Accept-Encoding: gzip, deflate\r\n' +
          'User-Agent: node-superagent/3.8.3\r\n' +
          'Content-Type: application/json\r\n' +
          'Content-Length: 39\r\n' +
          'Connection: close\r\n' +
          '\r\n',
        _onPendingData: [Function: noopPendingOutput],
        agent: Agent {
          _events: [Object: null prototype],
          _eventsCount: 1,
          _maxListeners: undefined,
          defaultPort: 80,
          protocol: 'http:',
          options: [Object],
          requests: {},
          sockets: [Object],
          freeSockets: {},
          keepAliveMsecs: 1000,
          keepAlive: false,
          maxSockets: Infinity,
          maxFreeSockets: 256
        },
        socketPath: undefined,
        method: 'POST',
        path: '/authenticate',
        _ended: true,
        res: IncomingMessage {
          _readableState: [ReadableState],
          readable: false,
          _events: [Object: null prototype],
          _eventsCount: 4,
          _maxListeners: undefined,
          socket: [Socket],
          connection: [Socket],
          httpVersionMajor: 1,
          httpVersionMinor: 1,
          httpVersion: '1.1',
          complete: true,
          headers: [Object],
          rawHeaders: [Array],
          trailers: {},
          rawTrailers: [],
          aborted: false,
          upgrade: false,
          url: '',
          method: null,
          statusCode: 302,
          statusMessage: 'Found',
          client: [Socket],
          _consuming: false,
          _dumped: false,
          req: [Circular],
          text: 'Found. Redirecting to /'
        },
        aborted: false,
        timeoutCb: null,
        upgradeOrConnect: false,
        parser: null,
        maxHeadersCount: null,
        [Symbol(kNeedDrain)]: false,
        [Symbol(isCorked)]: false,
        [Symbol(kOutHeaders)]: [Object: null prototype] {
          host: [Array],
          'accept-encoding': [Array],
          'user-agent': [Array],
          'content-type': [Array],
          'content-length': [Array]
        }
      },
      text: 'Found. Redirecting to /',
      body: {},
      files: undefined,
      buffered: true,
      headers: {
        'x-powered-by': 'Express',
        'set-cookie': [
          'access_token=kkkhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsInVzZXJpZCI6MSwiaWF0IjoxNTg5MDE3OTYwfQ.x4sRUhSqMaTFt2S3mrv6k3LOUecIgUJ4Cy8zWvdemss; Max-Age=3600; Path=/; Expires=Sat, 09 May 2020 10:52:40 GMT; HttpOnly'
        ],
        location: '/',
        vary: 'Accept',
        'content-type': 'text/plain; charset=utf-8',
        'content-length': '23',
        date: 'Sat, 09 May 2020 09:52:40 GMT',
        connection: 'close'
      },
      header: {
        'x-powered-by': 'Express',
        'set-cookie': [
          'access_token=lkJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsInVzZXJpZCI6MSwiaWF0IjoxNTg5MDE3OTYwfQ.x4sRUhSqMaTFt2S3mrv6k3LOUecIgUJ4Cy8zWvdemrr; Max-Age=3600; Path=/; Expires=Sat, 09 May 2020 10:52:40 GMT; HttpOnly'
        ],
        location: '/',
        vary: 'Accept',
        'content-type': 'text/plain; charset=utf-8',
        'content-length': '23',
        date: 'Sat, 09 May 2020 09:52:40 GMT',
        connection: 'close'
      },
      statusCode: 302,
      status: 302,
      statusType: 3,
      info: false,
      ok: false,
      redirect: true,
      clientError: false,
      serverError: false,
      error: false,
      created: false,
      accepted: false,
      noContent: false,
      badRequest: false,
      unauthorized: false,
      notAcceptable: false,
      forbidden: false,
      notFound: false,
      unprocessableEntity: false,
      type: 'text/plain',
      charset: 'utf-8',
      links: {},
      setEncoding: [Function: bound ],
      redirects: []
    }
JimmyTheCode
  • 3,783
  • 7
  • 29
  • 71
  • 1
    IIRC, in VSCode you can attach the process to Chrome, allowing you to debug using Chrome devtools, which lets you expand properties – CertainPerformance May 09 '20 at 10:13
  • That's typically something you do in your IDE or editor, as long as it features a JavaScript debugger ([example](https://code.visualstudio.com/docs/editor/debugging)). I'm not sure of what role Chrome plays here. – Álvaro González May 09 '20 at 14:17
  • Awesome @CertainPerformance . I hadn't tried debugging before and gave it a go. Really handy feature. The only thing it lacked was the ability to ctrl+f so I could check to see if certain properties existed. Otherwise a really good tool to solve much of my problem and much more! – JimmyTheCode May 10 '20 at 15:11

1 Answers1

1

OK, so I've got a solution, albeit a very verbose one.

Basically I clone the response object, then convert the all properties to enumerable. Then JSON.stringify still can't execute on the new object, since the object contains circular references. We have to provide a function to replace circular references with (I'm not sure... "undefined" maybe?). THEN we can stringify it. I've logged the object, then copied and pasted into a JSON Viewer. Problem solved I guess - but I'd like to think there's a neater solution out there.

           let resclone = {...res}
            //console.log(resclone);

            const toEnumerable = (obj) => {
                return Object.fromEntries(
                  Object.getOwnPropertyNames(obj).map(prop => [prop, obj[prop]])
                );
              };

              var enumerated = toEnumerable(resclone)

              const getCircularReplacer = () => {
                const seen = new WeakSet();
                return (key, value) => {
                  if (typeof value === "object" && value !== null) {
                    if (seen.has(value)) {
                      return;
                    }
                    seen.add(value);
                  }
                  return value;
                };
              };

              let stringify = JSON.stringify(enumerated, getCircularReplacer());
              console.log(stringify);
JimmyTheCode
  • 3,783
  • 7
  • 29
  • 71