Faraday: Defina automaticamente @handler para Faraday.default_adapter se não for especificado.

Criado em 22 fev. 2012  ·  35Comentários  ·  Fonte: lostisland/faraday

Normalmente, para nossos scripts simples, definimos Faraday.default_adapter uma vez no topo, no entanto, enquanto trabalhamos com o Github, que (sem ofensa) adora redirecionamentos, temos que usar faraday_middleware (bem, não precisamos usar) para seguir redirecionamentos que exigem que façamos um bloco (eu assumir) Eu acho que seria melhor se Faraday assumisse que o manipulador deve ser definido como Faraday.default_adapater se não for definido com uso no bloco, isso economiza alguma codificação e código redundante IMO.

refactoring

Comentários muito úteis

+1 para isso. No mínimo, um erro que nenhum adaptador foi especificado, ou melhor apenas usar o default_adapter se nada foi especificado.

Todos 35 comentários

Não tenho certeza sobre isso, mas vou deixá-lo aberto. A pilha padrão é UrlEncoded + default_adapter. Se você estiver definindo sua própria pilha, deve defini-la 100%, incluindo o adaptador. Mas é verdade que eu geralmente uso o default_adapter, então pode ser um padrão.

Eu estava pensando em refatorar adaptadores Faraday, tornando-os endpoints em vez de middleware (conforme #47). Esse recurso pode fazer parte dessa mudança.

:+1: Isso me mordeu pela segunda vez este ano. Você pensaria que eu aprenderia. Seria bom se fosse consertado.

Compromisso: Faraday.with_default_stack() , para que despejemos almas apenas tentando usar Faraday pela primeira vez não precisamos saber nada sobre "a pilha padrão" apenas para poder seguir os redirecionamentos. Razoável?

@jbrains Sim, eu percebo que isso não é amigável ao usuário. Podemos fazer com que um erro descritivo seja gerado se você não montou um adaptador ou se o montou no lugar errado.

Eu fiz isso no meu projeto:

        def faraday_with_default_adapter(base, &block)
          Faraday.new(base) { | connection |
            yield connection
            connection.adapter Faraday.default_adapter
          }
        end

Eu sei que você não quer apoiar todas as permutações, mas parece que quase todo mundo vai fazer isso eventualmente. :) Se eu soubesse como adicionar o bit UrlEncoded (ainda não me deparei com isso), adicionaria aqui.

Uma verificação de estilo lint com erro descritivo certamente ajudaria. Obrigado. Mesmo assim, um pouco de pokayoke nos ajudaria ainda mais.

Vou considerar enviar-lhe um pull request no futuro. Enquanto isso, obrigado.

Isso consumiu algumas horas de trabalho quando tentei fazer um upload e não especifiquei o adaptador padrão (que eu assumi que já estava definido, pois é o padrão). Continuei depurando e inspecionando os objetos de resposta/solicitação e não houve nenhum problema, exceto que estava faltando a temida linha de adaptador padrão.

Acho que isso deveria pelo menos estar documentado no README em algum lugar ou pelo menos me avisar que eu precisava de um adaptador explícito.

Obrigado!

Isso me mordeu hoje também com o seguinte exemplo:

conn = Faraday.new(url: "http://www.example.com") do |faraday|
  faraday.response :json, content_type: /\bjson$/
end

response = conn.get("stuff")

O erro apareceu no faraday_middleware quando ele tentou obter os cabeçalhos de resposta quando eles eram nil . Um pouco enganador. Foi tomada uma decisão sobre a "melhor maneira" de lidar com isso?

  • Use o adaptador padrão se não for especificado (o melhor IMO)
  • Gerar um erro se um não for especificado
  • Atualize o README

Eu ficaria mais do que feliz em enviar um PR

Não há necessidade de um PR. Tentaremos resolver isso na próxima versão.

Obrigado, @mislav.

Sim, perdi uma hora ontem perseguindo este aqui. É bom ver que uma correção está a caminho. Quando é provável que o próximo lançamento chegue? A última foi em janeiro, o que parece muito tempo.

Na quinta-feira, 2 de outubro de 2014 às 17h49, John Carney [email protected]
escreveu:

Quando é provável que o próximo lançamento chegue? A última foi em janeiro, o que parece
um tempo terrivelmente longo.

Como 0,8 e 0,9 devem ser congelados, a correção para isso provavelmente
só vem em 1.0, que não tenho certeza de quando será.

Que tal isso para um meio-termo simples: se for feita uma tentativa de fazer uma solicitação quando não houver adaptador, uma exceção será gerada.

Ou existe um caso de uso para "fazer solicitações" sem adaptador?

Em sex, 3 de outubro de 2014 às 14h07, John Bachir [email protected]
escreveu:

Que tal isso para um meio-termo simples: se for feita uma tentativa de fazer
uma solicitação quando não há adaptador, uma exceção é gerada.

Como detectamos se um adaptador está montado?

Observe que um adaptador personalizado implementado por alguém não tem necessariamente
para a subclasse Faraday::Adapter.

Ah, eu vejo. Como o adaptador é um irmão do outro middleware e a única API a ser testada é a API de rack padrão, não há como identificar se um middleware é um adaptador http. :sadtrombone:

Se isso for implementado, as alterações em #496 provavelmente poderão ser revertidas (se tiverem sido mescladas em primeiro lugar).

+1 para isso. No mínimo, um erro que nenhum adaptador foi especificado, ou melhor apenas usar o default_adapter se nada foi especificado.

O nome é confuso, quando você precisa adicionar middlewares, espera apenas adicionar middlewares e manter o default_adapter no lugar.

Isso é bobagem que acabamos sem nenhum adaptador. Você nunca quer isso...

Só quero garantir a todos que estamos discutindo internamente uma estratégia para gerenciar isso.
Eu sei que parece uma verificação fácil, mas como @mislav já explicou, temos um problema no momento relacionado à liberdade que as pessoas têm de adicionar adaptadores à pilha de middlewares.
Na verdade, no momento e "adaptador" nada mais é do que um middleware, como qualquer outro, realizando o pedido.
Agora, quando você define sua própria pilha de middlewares, perdemos a capacidade de detectar o adaptador de outros middlewares, a menos que você use o método #adapter ao construir a conexão. Infelizmente, o uso do mesmo não é obrigatório no momento, impossibilitando a detecção do adaptador.

Legal! Obrigado pela atenção aqui :)

Em 14 de novembro de 2016, às 14h45, Mattia [email protected] escreveu:

Só quero garantir a todos que estamos discutindo internamente uma estratégia
para gerenciar isso.
Eu sei que parece uma verificação fácil, mas como
@mislav já explicou que temos um problema no
momento relacionado com a liberdade que as pessoas têm de adicionar Adaptadores no
pilha de middlewares.
Na verdade, no momento e "adaptador" nada mais é do que um middleware, como
qualquer outro, realizando o pedido.
Agora, quando você define sua própria pilha de middlewares, perdemos a capacidade de
detectar o adaptador de outros middlewares, a menos que você use o #adapter
ao construir a conexão. Infelizmente, o uso não é
obrigatório no momento, impossibilitando a detecção do adaptador.


Você está recebendo isso porque comentou.
Responda a este e-mail diretamente, visualize-o no GitHub ou silencie ofio .

https://v2.developer.pagerduty.com/docs/authentication

Portanto, os documentos da API do PagerDuty, para ruby+faraday, exibem esse comportamento; se você apenas usar o código deles, não funcionará. (A menos que eles consertem, o que provavelmente farão agora que apontei a falta de um adaptador.)

Sinceramente, minha sugestão seria:

Se eu chamar "conn.get" e conn não tiver um adaptador, lance uma exceção me dizendo que . O comportamento atual é retornar imediatamente, mas não definir as coisas para os estados que Faraday descreve como resultantes da chamada get. Assim, por exemplo, ".status" ainda é nulo. Este é um comportamento realmente surpreendente! Eu diria que "não posso fazer nada porque não tenho ideia do que você quer que eu faça" provavelmente deveria produzir algum tipo de diagnóstico.

Oi @seebs , sei que parece bobo, mas expliquei por que isso não é tão fácil de fazer quanto poderia parecer no meu comentário anterior:

Quando você define sua própria pilha de middlewares, perdemos a capacidade de detectar o adaptador dos outros middlewares, a menos que você use o método #adapter ao construir a conexão. Infelizmente, o uso do mesmo não é obrigatório no momento, impossibilitando a detecção do adaptador.

Estou tentando rastrear o que acontece, e estou perdendo alguma coisa.

Se você fizer a coisa óbvia que muitas pessoas fazem, e não especificar o adaptador, quando você chamar get, você acabará no build_response do rack_builder, que faz app.call. E não tenho certeza de onde isso vai, porque não vejo onde o aplicativo foi definido.

Então eu acho que o que eu estou querendo saber é, se você nunca faz "adapter :foo", o que acaba recebendo a ligação?

Uma solução trivial:
def inicializar(manipuladores = [])
@handlers = manipuladores
se block_given?

  • self.adapter Faraday.default_adapter
    build(&Proc.novo)
    elsif @handlers.empty?

... Eu acho que isso funcionaria (-ish)?

Alternativamente, após build(&Proc.new), verifique se self.adapter foi configurado.

Embora adapter :foo seja a forma mais utilizada de configurar o adaptador, existem outras formas de fazer isso.
#adapter é na verdade apenas um auxiliar, mas você pode usar #use para colocar um adaptador na pilha:

conn = Faraday.new(url: "http://www.example.com") do |faraday|
  faraday.response :logger
  faraday.use Faraday::Adapter::NetHttp
end

Então, o que é um adaptador no momento? Nada mais do que um middleware que realiza a chamada e armazena o resultado em env . É por isso que não podemos simplesmente confiar no método #adapter sendo chamado. Não podemos confiar no middleware que funciona como um adaptador para herdar de Faraday::Adapter porque isso também não é um requisito.

A única solução é usar a versão 1.0 do Faraday para tornar obrigatório o uso do método #adapter , ou assumir que ele será usado e enviar o adaptador padrão na pilha se o método não for chamado.

Ainda estamos discutindo internamente qual seria a melhor solução, pois de uma forma ou de outra vamos acabar tendo pessoas obtendo resultados inesperados após a atualização.
Que é o que está acontecendo com muitas pessoas na primeira vez que usam Faraday, eu concordo, mas é definitivamente pior quando isso acontece em seu sistema de produção depois de executar bundle update :)

Acho que o que não estou entendendo é... Se você nunca configurou um adaptador, o que acaba atendendo a chamada e armazenando o resultado? Há uma invocação que, se você escolheu um adaptador, usa o método call() do adaptador, eu acho. Se você não escolheu um adaptador, qual código realmente é executado?

Foi aqui que eu escolhi o adaptador, sem usar o método #adapter .

  faraday.use Faraday::Adapter::NetHttp

Pegue o meu trecho do meu comentário anterior e tente, vai funcionar.
O problema é que você pode enviar um adaptador na pilha de várias maneiras e, uma vez lá, ele será usado na solicitação (chamando o método #call )

Desculpe, aparentemente não fui claro. Estou ciente de que você pode escolher um adaptador de várias maneiras.

Mas considere o erro comum de novato de não escolher um adaptador e, em seguida, chamar conn.get(...). O que realmente acaba acontecendo, além de "nada que tenha algum efeito"?

Tentei rastrear as chamadas e não consegui descobrir o que realmente acaba acontecendo. Parece que o Connection terá definido um get padrão que chama run_request. Isso, por sua vez, chama build_request e build_response, e acho que isso acaba no build_response() do rack_builder, que está chamando app.call(), e parece que o app está gerando um objeto Response que manipula a chamada(). Mas então eu fico confuso. Eu não vejo Response mesmo definindo um método call(), e não consigo descobrir o que acaba fazendo com que o método call() seja invocado.

Estou assumindo que há algo que tem um método de chamada, que é invocado. Se você selecionou um adaptador, obtém o método de chamada desse adaptador. Se você não selecionou um adaptador, de onde vem o método de chamada que realmente é executado?

Depois de configurar a solicitação e a resposta, Connection passa por todos os middlewares e chama o método call(env) neles, na mesma ordem em que a pilha é preenchida.
Ele não faz distinção entre "middlewares normais" e o adaptador, apenas assume que um dos middlewares é o adaptador. Se não houver nenhum "middleware adaptador" na pilha, todos os outros middlewares serão chamados (método call ), mas nenhum deles executará efetivamente a solicitação (essa é a função do adaptador).
O que significa que a resposta não terá o status, o corpo e todos os outros campos preenchidos pelo "middleware do adaptador".

Eu entendo que não é muito fácil, mas espero que agora esteja mais claro 😅

Ah-há! Isso é o que eu não consegui entender. Não me ocorreu que todos eles forneceriam funções call().

E se, depois de chamar tudo, o código gerasse uma exceção se o status não estiver definido? "StatusNotSetException: Status não foi definido. Provavelmente, seu middleware não especifica um adaptador para fazer a busca de rede."

Eu realmente adoraria ver isso corrigido!

Corrigido em #750 @iMacTia - você fecharia isso?

@olleolleolle sim, bom ponto! Eu pensei que isso seria fechado automaticamente por mencioná-lo :(

Parece que isso nunca foi lançado? Existe alguma chance de ver uma versão menor antes de 1.0? :speak_no_evil:

@franzliedke você está certo, isso está atualmente incluído na v1.0 e concordo que foi mesclado há algum tempo 😅.
No entanto, fizemos muitos progressos em direção à v1.0 e eu diria que estamos bastante perto de ultrapassar a linha.
Tente nos dar um pouco mais de tempo, vai valer a pena esperar 😃

Ótimo ouvir!

Desculpe por parecer um pouco exigente - eu sei como o código aberto pode ser estressante. Obrigado pelo ótimo software!

Não @franzliedke !
Aprecie o empurrão, devemos realmente mirar e lançar a v1.0 mais cedo ou mais tarde.
Assista ao repo se ainda não assiste para não perder o lançamento 👍

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

JasonBarnabe picture JasonBarnabe  ·  4Comentários

aleksb86 picture aleksb86  ·  3Comentários

subvertallchris picture subvertallchris  ·  5Comentários

mvastola picture mvastola  ·  4Comentários

mokolabs picture mokolabs  ·  3Comentários