Please make it possible to get response headers for query directly🙏

Hi there. Found similar issue posted but its closed without proper solution so I think this really should be reopened. My use case is to write test which can estimate projected app costs. For that I need to get access to response headers directly from client.query call. Maybe I am missing something, but I don’t see an obvious way to link headers for issued query with observer.

I created issue on GitHub with some ideas how to implement this:

Is this the older post you were referring to? If not, can you include a link for context?

Using the observer throughout an app or even in tests is awkward if you’re used to writing more pure functions. It is possible, though, to create a global/singleton type of object that gets you access to the observer result after each query.

I’ve got a simple Jest test that checks the stored observer value. So it’s possible, even if it relies on mutating a global value.

Here is one workaround idea.

I should highlight first that a new function that returns the full result in addition to the usual fauna response would be cool.

Extending the Client

Here is an example of extending the Client class. This new class has a function that returns the usual result and the full request result.

class ObserverClient extends Client {
  constructor(opts) {
    super({
      ...opts,
      // overrides observer to update a member variable
      observer: (res) => {
        this._observerResult = res
      },
    })
    this._observerResult = null
  }

  async queryFullResponse(expr, options) {
    const result = await this.query(expr, options)
    // dumb way to clone the result
    const requestResult = JSON.parse(JSON.stringify(this._observerResult) )
    // return both
    return [result, requestResult]
  }
}

then use it later

// initialize like a normal client
const observerClient = new ObserverClient({
  secret: FAUNA_KEY,
  domain: FAUNA_DOMAIN
})

// ...

const [res, requestResult] = await observerClient.queryFullResponse(q.Paginate(q.Collections()))

console.log(res)
console.log(requestResult.responseHeaders['x-byte-read-ops'])

// console

{
  data: [
    Collection("things")
  ]
}

"1"

I forked by Jest code to test this out and it works pretty nicely!

Cheers.

1 Like

Thanks, @ptpaterson!

I have managed to incorporate solution build on top of your idea to override Client and update global variable to store last response in my code and it seems to work nicely. :+1:

And yes, you link to correct issue I’ve mentioned, sorry for not including the link myself.

I think this code is more customizable, so by providing option to return response we can get
it in a standard client.query method invocation in a backward compatible way:

class ObserverClient extends faunadb.Client {
  constructor(opts) {
    super({
      ...opts,
      // overrides observer to save last response
      observer: (res) => {
        this._lastResponse = res
        opts.observer && opts.observer(res) // in case we have custom observer passed.
      },
    })
    this._lastResponse = null
  }

  async query(expr, options) {
    const { returnResponse, ...rest } = options 
    const result = await super.query(expr, rest)
    return returnResponse ? { result, response: this._lastResponse } : result
  }
}
1 Like

Neat!

I’d recommend to be careful returning a reference to the member variable _lastResponse. Doing so will be full of side effects and race conditions; It would be good to return a clone of the response. Consider if you wanted to do a Promise.all of several queries, using the member directly you would end up setting all of the responses to the one that finishes last.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.