Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
iMacTia committed Apr 11, 2021
0 parents commit 1a6662b
Show file tree
Hide file tree
Showing 18 changed files with 301 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.idea/
.bundle/
.yardoc
_yardoc/
coverage/
doc/
pkg/
spec/reports/
tmp/

*.gem
gemfile.lock

.rvmrc
.ruby-version

.rspec_status
3 changes: 3 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--require spec_helper
--format documentation
--color
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# frozen_string_literal: true

source 'https://rubygems.org'
gemspec
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2020 Jan van der Pas

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Faraday Adapter Template

This repo is a template for building [Faraday][faraday] adapters.
Faraday is an HTTP client library that provides a common interface over many adapters.
Every adapter is defined into it's own gem. Use this repository to create your own adapter gem.

## Getting Started

### Setting up and cloning the repo

You can start using GitHub's [Use this template][use-template] button.
![Use this template](https://docs.github.com/assets/images/help/repository/use-this-template-button.png)

This will create a repository based off from this template.
After that is created, you can clone it locally to start working on it.

### Refactoring the template

The next step is for you to find and replace all the "parametrised" names in this template and change them to make it unique.
First of all, you should decide on the name of your adapter.
The current convention (which is by no means mandatory) is to call adapter gems as `faraday-<adapter_name>`.
Here are some examples:

* `HTTP`: [`faraday-http`][faraday-http]
* `Net::HTTP`: [`faraday-net_http`][faraday-net_http]

In this template repository, the placeholder for your chosen adapter name is `MyAdapter` (`my_adapter`).
So once you decide on the final name you want to use you should update all occurrences of `MyAdapter` and all files with `my_adapter` in their name with the new name you chose.

### Main implementation

The bulk of the implementation is in the `Faraday::Adapter::MyAdapter` class.
We've added lots of comments in there to guide you through it, but if you have any doubt/question please don't hesitate to get in touch!

[faraday]: https://github.com/lostisland/faraday
[faraday-http]: https://github.com/lostisland/faraday-http
[faraday-net_http]: https://github.com/lostisland/faraday-net_http
[use-template]: https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template
8 changes: 8 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

require 'bundler/gem_tasks'
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec)

task default: :spec
6 changes: 6 additions & 0 deletions bin/ci-lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle exec rubocop --format progress
6 changes: 6 additions & 0 deletions bin/ci-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle exec rspec
15 changes: 15 additions & 0 deletions bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require 'bundler/setup'
require 'faraday-my_adapter'

# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.

# (If you use this, don't forget to add pry to your Gemfile!)
# require "pry"
# Pry.start

require 'irb'
IRB.start(__FILE__)
7 changes: 7 additions & 0 deletions bin/setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

gem install bundler
bundle install
7 changes: 7 additions & 0 deletions bin/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle exec rubocop -a --format progress
bundle exec rspec
34 changes: 34 additions & 0 deletions faraday-my_adapter.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

require_relative 'lib/faraday/my_adapter/version'

Gem::Specification.new do |spec|
spec.name = 'faraday-my_adapter'
spec.version = Faraday::MyAdapter::VERSION
spec.authors = ['Your Name']
spec.email = ['your_name@gmail.com']

spec.summary = 'Faraday adapter for MyAdapter'
spec.description = 'Faraday adapter for MyAdapter'
spec.homepage = 'https://github.com/lostisland/faraday-my_adapter'
spec.license = 'MIT'

spec.required_ruby_version = Gem::Requirement.new('>= 2.4.0')

spec.metadata['homepage_uri'] = spec.homepage
spec.metadata['source_code_uri'] = 'https://github.com/lostisland/faraday-my_adapter'
spec.metadata['changelog_uri'] = 'https://github.com/lostisland/faraday-my_adapter'

spec.files = Dir.glob('lib/**/*') + %w[README.md LICENSE.md]
spec.require_paths = ['lib']

spec.add_development_dependency 'faraday', '~> 1.0'

spec.add_development_dependency 'bundler', '~> 2.0'
spec.add_development_dependency 'rake', '~> 13.0'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'simplecov', '~> 0.19.0'

spec.add_development_dependency 'multipart-parser', '~> 0.1.1'
spec.add_development_dependency 'webmock', '~> 3.4'
end
67 changes: 67 additions & 0 deletions lib/faraday/adapter/my_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# frozen_string_literal: true

module Faraday
class Adapter
# This class provides the main implementation for your adapter.
# There are some key responsibilities that your adapter should satisfy:
# * Initialize and store internally the client you chose (e.g. Net::HTTP)
# * Process requests and save the response (see `#call`)
class MyAdapter < Faraday::Adapter
# The initialize method is lazy-called ONCE when the connection stack is built.
# See https://github.com/lostisland/faraday/blob/master/lib/faraday/rack_builder.rb
#
# @param app [#call] the "rack app" wrapped in middleware. See https://github.com/lostisland/faraday/blob/master/lib/faraday/rack_builder.rb#L157
# @param opts [Hash] the options hash with all the options necessary for the adapter to correctly configure itself.
# These are automatically stored into `@connection_options` when you call `super`.
# @param block [Proc] the configuration block for the adapter. This usually provides the possibility to access the internal client from the outside
# and set properties that are not included in Faraday's API. It's automatically stored into `@config_block` when you call `super`.
def initialize(app = nil, opts = {}, &block)
super(app, opts, &block)
end

# This is the main method in your adapter. Since an adapter is a middleware, this method will be called FOR EVERY REQUEST.
# The main task of this method is to perform a call using the internal client and save the response.
# Since this method is not called directly f`rom the outside, you'll need to use `env` in order to:
# * Get the request parameters (see `Faraday::Env` and `Faraday::RequestOptions` for the full list). This includes processing:
# * The request method, url, headers, parameters and body
# * The SSL configuration (env[:ssl])
# * The request configuration (env[:request]), i.e. things like: timeout, proxy, etc...
# * Set the response attributes. This can be done easily by calling `save_response`. These include:
# * Response headers and body
# * Response status and reason_phrase
#
# @param env [Faraday::Env] the environment of the request being processed
def call(env)
# First thing to do should be to call `super`. This will take care of the following for you:
# * Clear the body if the request supports a body
# * Initialize `env.response` to a `Faraday::Response`
super

# Next you want to configure your client for the request and perform it, obtaining the response.
response = {} # Make call using client

# Now that you got the response in the client's format, you need to call `save_response` to store the necessary
# details into the `env`. This method accepts a block to make it easier for you to set response headers using
# `Faraday::Utils::Headers`. Simply provide a block that given a `response_headers` hash sets the necessary key/value pairs.
# Faraday will automatically take care of things like capitalising keys and coercing values.
save_response(env, response.status, response.body, response.headers, response.reason_phrase) do |response_headers|
response.headers.each do |key, value|
response_headers[key] = value
end
end

# NOTE: An adapter `call` MUST return the `env.response`. If `save_response` is the last line in your `call`
# method implementation, it will automatically return the response for you.
# Otherwise, you'll need to manually do so. You can do this with any (not both) of the following lines:
# * @app.call(env)
# * env.response
# Finally, it's good practice to rescue client-specific exceptions (e.g. Timeout, ConnectionFailed, etc...)
# and re-raise them as Faraday Errors. Check `Faraday::Error` for a list of all errors.
rescue MyAdapterTimeout => e
# Most errors allow you to provide the original exception and optionally (if available) the response, to
# make them available outside of the middleware stack.
raise Faraday::TimeoutError, e
end
end
end
end
17 changes: 17 additions & 0 deletions lib/faraday/my_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

require_relative 'adapter/my_adapter'
require_relative 'my_adapter/version'

module Faraday
module MyAdapter
# Faraday allows you to register your middleware for easier configuration.
# This step is totally optional, but it basically allows users to use a custom symbol (in this case, `:my_adapter`),
# to use your adapter in their connections.
# After calling this line, the following are both valid ways to set the adapter in a connection:
# * conn.adapter Faraday::Adapter::MyAdapter
# * conn.adapter :my_adapter
# Without this line, only the former method is valid.
Faraday::Adapter.register_middleware(my_adapter: Faraday::Adapter::MyAdapter)
end
end
7 changes: 7 additions & 0 deletions lib/faraday/my_adapter/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module Faraday
module MyAdapter
VERSION = '0.1.0'
end
end
17 changes: 17 additions & 0 deletions spec/faraday/adapter/my_adapter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

RSpec.describe Faraday::Adapter::MyAdapter do
# Since not all adapters support all the features Faraday has to offer, you can use the `features` method to turn on
# only the ones you know you can support.
# TODO: provide the full list of available features!
features :request_body_on_query_methods,
:reason_phrase_parse,
:compression,
:streaming,
:trace_method

# Runs the tests provide by Faraday, according to the features specified above.
it_behaves_like 'an adapter'

# You can then add any other test specific to this adapter here...
end
7 changes: 7 additions & 0 deletions spec/faraday/my_adapter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

RSpec.describe Faraday::MyAdapter do
it 'has a version number' do
expect(Faraday::MyAdapter::VERSION).to be_a(String)
end
end
20 changes: 20 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

require 'faraday'
require 'faraday/my_adapter'
# This is the magic bit. It requires a tests suite from the Faraday gem that you can run against your adapter
require 'faraday_specs_setup'

RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
config.example_status_persistence_file_path = '.rspec_status'

# Disable RSpec exposing methods globally on `Module` and `main`
config.disable_monkey_patching!

config.expect_with :rspec do |c|
c.syntax = :expect
end

config.order = :random
end

0 comments on commit 1a6662b

Please sign in to comment.