Typhoeus 1.4.1 e como utilizar em seu projeto Ruby
Recebemos uma solicitação para criar um vídeo em nosso canal, e estamos empenhados em oferecer também conteúdo escrito para que todos possam encontrar alternativas educacionais. Buscarei explicar da melhor maneira possível; embora os vídeos tenham suas vantagens, aqui o conteúdo escrito também pode ser extremamente útil.
Essa solicitação foi enviada através do Discord, então vamos lá.
Requisitos:
- Ruby: versão 3.2.0
- Bundler: versão 2.4.12
Agradecemos pela interação da nossa comunidade e pela oportunidade de atender às suas necessidades educacionais. Fiquem atentos aos próximos artigos e vídeos, pois compartilharemos tutoriais e dicas. Estamos animados em fornecer esse conteúdo. Caso tenham mais sugestões ou solicitações, não hesitem em compartilhar conosco no Discord ou em outras plataformas.
Abra o seu terminal e digite os comandos abaixo:
➜ language mkdir brasilapi
➜ language cd brasilapi && bundle init
Writing new Gemfile to /Users/ropeixoto/Project/skill.dev/youtube/languages/Ruby/language/brasilapi/Gemfile
➜ brasilapi mkdir lib
➜ brasilapi
- Vamos criar uma nova pasta, com o comando
mkdir
vamos criar com o nomebrasilapi
- depois com o comando
cd brasilapi
acessamos a pasta que criamos, e com o&&
dizemos que ele irá executar os dois comandos no bash, então depois vamos inicializar o projetobundle init
, ele irá gerar oGemfile
- depois criamos a pasta
mkdir lib
feito? vamos abrir o nosso editor favorite, abre o seu, beleza? o meu vai ser o visual studio code. então code .
assim, deveria abrir por causa do . a pasta atual no VSCode.
Abra o brasilapi/Gemfile
e adicione as gems
# frozen_string_literal: true
source "https://rubygems.org"
# gem "rails"
gem 'typhoeus' # Lib para fazermos requests com o protocolo HTTP
gem 'rspec' # Lib para os testes automatizados
gem 'pry' # Lib para fazer debugger mais poderoso
Execute o comando:
bundle install
Depois vamos gerar os arquivos do rspec
com o comando:
rspec --init
Você verá no seu console uma criação dos arquivos .rspec
e spec/spec_helper.rb
Vamos agora verificar a documentação da BrasilApi e vamos iniciar os nossos testes, como sempre, crie um arquivo na pasta spec/bank_spec.rb
require 'spec_helper'
require_relative '../lib/bank'
RSpec.describe Bank do
let(:bank_response) { Bank.new }
describe '.all' do
it 'does return all banks' do
expect(bank_response.all).to be_kind_of(Array)
expect(bank_response.all.first).to have_key('ispb')
expect(bank_response.all.first).to have_key('name')
expect(bank_response.all.first).to have_key('code')
expect(bank_response.all.first).to have_key('fullName')
end
end
end
Execute o comando rspec spec
➜ brasilapi rspec spec
An error occurred while loading ./spec/bank_spec.rb.
Failure/Error:
RSpec.describe Bank do
let(:bank_response) { Bank.new }
describe '.all' do
it 'does return all banks' do
expect(bank_response.all).to be_kind_of(Array)
expect(bank_response.all.first).to have_key(:ispb)
expect(bank_response.all.first).to have_key(:name)
expect(bank_response.all.first).to have_key(:code)
expect(bank_response.all.first).to have_key(:fullName)
end
NameError:
uninitialized constant Bank
# ./spec/bank_spec.rb:4:in `<top (required)>'
No examples found.
Finished in 0.00003 seconds (files took 0.14774 seconds to load)
0 examples, 0 failures, 1 error occurred outside of examples
Agora precisamos criar o arquivo lib/bank.rb
e vamos iniciar a mágica:
require 'typhoeus'
require 'pry'
require 'json'
class Bank
URL = 'https://brasilapi.com.br/api/banks/v1'
HEADERS = { 'Content-Type' => 'application/json' }
def all
bank_request = request(URL, :get).run
JSON.parse(bank_request.body)
end
private
def request(url, method)
Typhoeus::Request.new(
url,
method: method,
headers: HEADERS
)
end
end
Precisamos chamar as bibliotecas que são: typhoeus para a request, pry para debugger e a json para que eu possa transformar string
em hash
.
Na linha 5 criamos a classe e criamos duas constantes URL e HEADERS, esse são importantes pelo que a documentação nos mostra: https://brasilapi.com.br/docs#tag/BANKS
depois criamos um método privado request recebendo url como parâmetro e também o método get, post e etc... e depois inicializamos o objeto Typhoeus e passamos os parâmetros esperados.
então, criamos um all para podermos utilizar o endpoint principal e vamos complementar.
e agora vamos adicionar mais um endpooint
vai no arquivo spec/bank_spec.rb
e adicione o novo bloco de código .find_by_id
:
require 'spec_helper'
require_relative '../lib/bank'
RSpec.describe Bank do
let(:bank_response) { Bank.new }
describe '.all' do
it 'does return all banks' do
expect(bank_response.all).to be_kind_of(Array)
expect(bank_response.all.first).to have_key('ispb')
expect(bank_response.all.first).to have_key('name')
expect(bank_response.all.first).to have_key('code')
expect(bank_response.all.first).to have_key('fullName')
end
end
describe '.find_by_id' do
it 'does return all banks' do
code = 1
expect(bank_response.find_by_id(code)).to be_kind_of(Hash)
expect(bank_response.find_by_id(code)).to have_key('ispb')
expect(bank_response.find_by_id(code)).to have_key('name')
expect(bank_response.find_by_id(code)).to have_key('code')
expect(bank_response.find_by_id(code)).to have_key('fullName')
end
end
end
Adicione a URL e a interpolação com o code
e assim, você conseguirá ter uma nova request, somente modificando um trecho do código:
require 'typhoeus'
require 'pry'
require 'json'
class Bank
URL = 'https://brasilapi.com.br/api/banks/v1'
HEADERS = { 'Content-Type' => 'application/json' }
def all
banks_request = request(URL, :get).run
JSON.parse(banks_request.body)
end
def find_by_id(code)
bank_request = request("#{URL}/#{code}", :get).run
JSON.parse(bank_request.body)
end
private
def request(url, method)
Typhoeus::Request.new(
url,
method: method,
headers: HEADERS
)
end
end
Depois, vamos executar os nossos testes novamente, e estará perfeito passando o nosso exemplo:
rspec spec
saída
➜ brasilapi rspec
.
Finished in 0.5483 seconds (files took 0.30107 seconds to load)
1 example, 0 failures
➜ brasilapi
Algo que eu quero que você perceba é que fizemos uma request, então a todo momento que formos executar os testes, vamos ficar fazendo request a api? isso poderá ser um grande problema, sempre pense, tudo na computação é custo, se você utilizar o endpoint a todo momento a api te limitará, com um rate limite ou até mesmo, será bloqueado da api, então vamos e precisamos evitar.
Vamos para a parte II 😄 siga para os próximos capítulos.
Agora aparecerá o vcr
vídeocacete em português. Vamos adicionar a gem no arquivo Gemfile
, por que precisamos fazer talvez uma unica request e não fazer mais, salvar os dados localmente, certo?
então abra seu arquivo Gemfile
e adicionar o código gem 'vcr'
:
# frozen_string_literal: true
source "https://rubygems.org"
# gem "rails"
gem 'typhoeus'
gem 'rspec'
gem 'pry'
gem 'vcr' # Essa gem
Vamos criar o Diretório para as Cassetes:
Certifique-se de criar o diretório para armazenar as cassetes. No seu projeto, crie a seguinte estrutura de diretórios:
spec/fixtures/vcr_cassettes
e adicione também a pasta e arquivo spec/support/vcr_setup.rb
# spec/support/vcr_setup.rb
require 'vcr'
VCR.configure do |config|
config.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
config.hook_into :typhoeus
end
e depois abra o arquivo spec/spec_helper.rb
require_relative 'support/vcr_setup' # adicionar
Altere o código do arquivo spec/bank_spec.rb
e verifique que adicionamos o vcr e um caminho que salvará o payload, vá na pasta dentro do seu arquivo, após executar os testes e verá uns dados yml.
require 'spec_helper'
require_relative '../lib/bank'
require 'vcr'
RSpec.describe Bank do
let(:bank_response) { Bank.new }
describe '.all' do
it 'does return all banks' do
VCR.use_cassette('bank/all') do
expect(bank_response.all).to be_kind_of(Array)
expect(bank_response.all.first).to have_key('ispb')
expect(bank_response.all.first).to have_key('name')
expect(bank_response.all.first).to have_key('code')
expect(bank_response.all.first).to have_key('fullName')
end
end
end
describe '.find_by_id', vcr: { cassette_name: 'bank/find_by_id' } do
it 'does return all banks' do
VCR.use_cassette('bank/find_by_id') do
code = 1
expect(bank_response.find_by_id(code)).to be_kind_of(Hash)
expect(bank_response.find_by_id(code)).to have_key('ispb')
expect(bank_response.find_by_id(code)).to have_key('name')
expect(bank_response.find_by_id(code)).to have_key('code')
expect(bank_response.find_by_id(code)).to have_key('fullName')
end
end
end
end
Verifique agora sua pasta brasilapi/spec/fixtures/vcr_cassettes/bank/*.yml
Poderá verificar que há o payload organizado em yml e a partir de agora ele vai olhar para esse arquivo, caso queira fazer request novamente, basta remover o arquivo.
Agora testando o 404 que está na documentação, adicionamos a linha 33:
context 'when error' do it 'does return BANK_CODE_NOT_FOUND for non-existing bank code' do
require 'spec_helper'
require_relative '../lib/bank'
require 'vcr'
RSpec.describe Bank do
let(:bank_response) { Bank.new }
describe '.all' do
context 'when is success' do
it 'does return all banks' do
VCR.use_cassette('bank/all') do
expect(bank_response.all).to be_kind_of(Array)
expect(bank_response.all.first).to have_key('ispb')
expect(bank_response.all.first).to have_key('name')
expect(bank_response.all.first).to have_key('code')
expect(bank_response.all.first).to have_key('fullName')
end
end
end
end
describe '.find_by_id', vcr: { cassette_name: 'bank/find_by_id' } do
context 'when success' do
it 'does return all banks' do
VCR.use_cassette('bank/find_by_id') do
code = 1
expect(bank_response.find_by_id(code)).to be_kind_of(Hash)
expect(bank_response.find_by_id(code)).to have_key('ispb')
expect(bank_response.find_by_id(code)).to have_key('name')
expect(bank_response.find_by_id(code)).to have_key('code')
expect(bank_response.find_by_id(code)).to have_key('fullName')
end
end
end
context 'when error' do
it 'does return BANK_CODE_NOT_FOUND for non-existing bank code' do
VCR.use_cassette('bank/find_by_id_404') do
bank_id = 'non_existing_code'
response = bank_response.find_by_id(bank_id)
expect(response['message']).to eq('Código bancário não encontrado')
expect(response['type']).to eq('BANK_CODE_NOT_FOUND')
end
end
end
end
end
executamos o código
rspec spec
Pronto, chegamos ao fim, tudo funcionando e você evitando a quantidade de requisições desnecessárias.