Um dos provedores de serviço que estou usando tem URLs como este: https://service.com/service:search
. É assim que configuramos o Faraday:
class Provider::Client
...
delegate :post, :patch, :delete, :put, to: :client
def client
Faraday.new(url: 'https://service.com/') do |faraday|
faraday.headers = headers.merge(content_type: content_type)
faraday.response(:json, content_type: CONTENT_TYPE)
faraday.basic_auth(USER, PASSWORD)
faraday.adapter(Faraday.default_adapter)
end
end
end
e quando eu o invoco
data = Provider::Client.post(
"service:search?limit=#{LIMIT}&offset=#{offset}", search_params
)
mas quando faço isso com o URL em questão, recebo o seguinte:
URI::InvalidURIError: query conflicts with opaque
from /Users/luiz/.rbenv/versions/2.7.1/lib/ruby/2.7.0/uri/generic.rb:832:in `query='
Presumo que seja algo relacionado ao adaptador net / http, pois é o adaptador padrão, então fiz a mesma chamada manualmente
require "uri"
require "net/http"
url = URI("https://service.com/service:search?limit=50&offset=400")
https = Net::HTTP.new(url.host, url.port);
https.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Accept"] = "custom_header"
request["Authorization"] = "Basic xxx="
request["Content-Type"] = "application/json"
request.body = "long_json"
response = https.request(request)
puts response.read_body
e isso realmente funciona, então eu suspeito que algo em Faraday está validando este URL de uma maneira diferente de net / http
Olá @luizkowalski , a exceção vem de URI
e é gerada nas primeiras linhas do método query=
:
def query=(v)
return <strong i="9">@query</strong> = nil unless v
raise InvalidURIError, "query conflicts with opaque" if <strong i="10">@opaque</strong>
...
end
Faraday faz alguma mágica interna no url do pedido, dividindo-o e recombinando-o para ajudar em algumas transformações comuns, e presumo que em algum momento isso pode fazer com que @opaque
seja definido graças à presença de :
no URL.
Rastreei o problema até esta linha: https://github.com/lostisland/faraday/blob/c26df87b8653db4f270e3bcdc7a15bcdd2dd5cae/lib/faraday/connection.rb#L525
Usando seu código de exemplo, base
seria #<URI::HTTPS https://service.com/>
e url
seria service:search?limit=50&offset=400
.
Agora, curiosamente, se o segundo parâmetro do método +
para URI contém um :
, parece que o resultado é bastante inesperado!
2.7.1 > url
=> "service:search?limit=50&offset=400"
2.7.1 > base
=> #<URI::HTTPS https://service.com/>
2.7.1 > base + url
=> #<URI::Generic service:search?limit=50&offset=400>
Por algum motivo, base
é removido e apenas o url é deixado.
A correção é muito fácil neste caso, é suficiente apenas acrescentar /
ao url e as coisas funcionam conforme o esperado:
data = Provider::Client.post(
"/service:search?limit=#{LIMIT}&offset=#{offset}", search_params
)
No entanto, isso não funciona em todos os casos, pois pode ser necessário anexar um caminho relativo ao base
que não pode começar com /
.
Experimente antes de /
e deixe-me saber se funciona, mas deixarei este problema em aberto para dar uma olhada e encontrar uma maneira possível de corrigir essa linha de código em Faraday para que funciona neste caso.
Se você quiser tentar você mesmo, ficaria feliz em revisar um PR 😃
@iMacTia funcionou agora. O URL base é: https://service.com/api
. Quando adicionei /
a service:search
, obtive um erro e notei que /api
tinha sumido do URL base, então adicionei /api/service:search
e agora está tudo bem
@luizkowalski perfeito, sim, é exatamente o que eu quis dizer com
No entanto, isso não funciona em todos os casos, pois pode ser necessário anexar um caminho relativo à base que não pode começar com /.
Como faraday assume que a URL fornecida é absoluta se começa com /
e remove o caminho fornecido para a base.
Que bom que você já encontrou a solução alternativa, mas isso ainda deve ser corrigido adequadamente para que a solução alternativa não seja mais necessária
Comentários muito úteis
@luizkowalski perfeito, sim, é exatamente o que eu quis dizer com
Como faraday assume que a URL fornecida é absoluta se começa com
/
e remove o caminho fornecido para a base.Que bom que você já encontrou a solução alternativa, mas isso ainda deve ser corrigido adequadamente para que a solução alternativa não seja mais necessária