Module: ElasticGraph::Support::FaradayMiddleware

Defined in:
lib/elastic_graph/support/faraday_middleware/support_timeouts.rb,
lib/elastic_graph/support/faraday_middleware/msearch_using_get_instead_of_post.rb

Constant Summary collapse

SupportTimeouts =

Faraday supports specifying a timeout at both the client level (when building the Faraday connection) or on a per-request basis. We want to specify it on a per-request basis, but unfortunately, the Elasticsearch/OpenSearch clients don’t provide any per-request API to specify the timeout (it only supports it when instantiating your client).

This middleware helps us work around this deficiency by looking for the TIMEOUT_MS_HEADER. If present, it deletes it from the headers and instead sets it as the request timeout.

::Data.define(:app) do
  # @implements SupportTimeouts
  def call(env)
    if (timeout_ms = env.request_headers.delete(TIMEOUT_MS_HEADER))
      env.request.timeout = timeout_ms / 1000.0
    end

    app.call(env)
  rescue ::Faraday::TimeoutError
    raise RequestExceededDeadlineError, "Datastore request exceeded timeout of #{timeout_ms} ms."
  end
end
MSearchUsingGetInsteadOfPost =

Custom Faraday middleware that forces ‘msearch` calls to use an HTTP GET instead of an HTTP POST. While not necessary, it preserves a useful property: all “read” calls made by ElasticGraph use an HTTP GET, and HTTP POST requests are “write” calls. This allows the access policy to only grant HTTP GET access from the GraphQL endpoint, which leads to a more secure setup (as the GraphQL endpoint can be blocked from performing any writes).

Note: before elasticsearch-ruby 7.9.0, ‘msearch` used an HTTP GET request, so this simply restores that behavior. This results in an HTTP GET with a request body, but it works just fine and its what the Ruby Elasticsearch client did for years.

For more info, see: github.com/elastic/elasticsearch-ruby/issues/1005

::Data.define(:app) do
  # @implements MSearchUsingGetInsteadOfPost
  def call(env)
    env.method = :get if env.url.path.to_s.end_with?("/_msearch")
    app.call(env)
  end
end