Skip to content

Commit

Permalink
Enable rack 3.0 (#171)
Browse files Browse the repository at this point in the history
* Test for rack 3.0

* Fix build for rack 3.0

* Add rackup as a dev dependency

* Pass through Rack::Response

* Improve examples
  • Loading branch information
mkon authored Oct 5, 2022
1 parent 8fd1982 commit ddcff9d
Show file tree
Hide file tree
Showing 19 changed files with 73 additions and 38 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ jobs:
rspec:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
activesupport: ['6.1', '7.0']
ruby: ['2.7', '3.0', '3.1', '3.2']
rack: ['2.2', '3.0']
ruby: ['2.7', '3.1', '3.2']
steps:
- uses: actions/checkout@v2
- name: Set up Ruby
Expand All @@ -34,5 +36,6 @@ jobs:
cache-version: ${{ matrix.activesupport }}
env:
ACTIVESUPPORT: ${{ matrix.activesupport }}
RACK: ${{ matrix.rack }}
- name: Rspec
run: bundle exec rspec
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ end
if (version = ENV['ACTIVESUPPORT'])
gem 'activesupport', "~> #{version}.0"
end

if (version = ENV['RACK'])
gem 'rack', "~> #{version}.0"
end
3 changes: 2 additions & 1 deletion api_valve.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ Gem::Specification.new do |s|
s.add_dependency 'activesupport', '>= 6.1', '< 7.1'
s.add_dependency 'faraday', '>= 0.14', '<= 2.5.2'
s.add_dependency 'multi_json', '~> 1.13'
s.add_dependency 'rack', '~> 2'
s.add_dependency 'rack', '>= 2', '< 4'

s.add_development_dependency 'json_spec', '~> 1.1'
s.add_development_dependency 'rack-test', '~> 2.0'
s.add_development_dependency 'rackup'
s.add_development_dependency 'rspec', '~> 3.7'
s.add_development_dependency 'rubocop', '1.36.0'
s.add_development_dependency 'rubocop-rspec', '2.13.1'
Expand Down
6 changes: 3 additions & 3 deletions examples/aggregation/config.ru
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'api_valve'
require 'byebug'

app = Rack::Builder.new do
use ApiValve::Middleware::ErrorHandling
Expand All @@ -9,11 +10,10 @@ app = Rack::Builder.new do
threads = (1..5).map do |i|
Thread.new { forwarder.call request, 'path' => "posts/#{i}" }
end
threads.each(&:join)
body = threads.map(&:value).map do |rack_response|
JSON.parse(rack_response[2].first)
JSON.parse(rack_response.body.first)
end.to_json
[200, {'Content-Type' => 'application/json'}, [body]]
Rack::Response.new(body, 200, {'Content-Type' => 'application/json'})
end
end

Expand Down
9 changes: 3 additions & 6 deletions examples/basic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ rackup -q -p 8080

As you can see from the `config.ru`, it will forward all requests according to this table:

| Route | Target |
|----------------|-------------------------------|
| /oauth/ | http://auth.host/oauth/ |
| /oauth/token | http://auth.host/oauth/token |
| /api/ | http://api.host/api/ |
| /api/something | http://api.host/api/something |
| Route | Target |
|----------------|------------------------------------------------|
| /api/* | http://jsonplaceholder.typicode.com/* |
6 changes: 3 additions & 3 deletions examples/basic/config.ru
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ require 'api_valve'

app = Rack::Builder.new do
map '/api' do
run ApiValve::Proxy.from_hash(endpoint: 'http://api.host/api/')
run ApiValve::Proxy.from_hash(endpoint: 'https://jsonplaceholder.typicode.com')
end
map '/oauth' do
run ApiValve::Proxy.from_hash(endpoint: 'http://auth.host/oauth/')
map '/health' do
run ->(_env) { [200, {}, ['']] }
end
end

Expand Down
14 changes: 7 additions & 7 deletions examples/routing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ rackup -q -p 8080

As you can see from the `config.ru`, it will forward all requests according to this table:

| Method | Route | Target |
|--------|-----------------------|-----------------------|
| GET | /api/* | http://api.host/api/* |
| GET | /api/prefix/* | http://api.host/api/* |
| POST | * | HTTP Error 403 |
| PUT | * | HTTP Error 403 |
| PATCH | * | HTTP Error 403 |
| Method | Route | Target |
|--------|-------------------|---------------------------------------------|
| GET | /api/* | http://jsonplaceholder.typicode.com/* |
| GET | /api/customers/* | http://jsonplaceholder.typicode.com/users/* |
| POST | * | HTTP Error 403 |
| PUT | * | HTTP Error 403 |
| PATCH | * | HTTP Error 403 |
10 changes: 7 additions & 3 deletions examples/routing/config.ru
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
require 'api_valve'
require 'byebug'

app = Rack::Builder.new do
use ApiValve::Middleware::ErrorHandling
use ApiValve::Middleware::Logging

map '/api' do
run ApiValve::Proxy.from_hash(
endpoint: 'http://api.host/api/',
endpoint: 'http://jsonplaceholder.typicode.com',
routes: [
{
method: 'get',
path: %r{^/prefix/(?<final_path>.*)},
request: {path: '%{final_path}'}
path: %r{^/customers/(?<path>.*)},
request: {path: '/users/%{path}'}
},
{
method: 'get'
},
{
method: 'post',
Expand Down
1 change: 1 addition & 0 deletions lib/api_valve.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
require 'faraday'
require 'multi_json'
require 'logger'
require 'rack'

module ApiValve
autoload :Benchmarking, 'api_valve/benchmarking'
Expand Down
4 changes: 2 additions & 2 deletions lib/api_valve/error_responder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ def initialize(error)
end

def call
[
Rack::Response[
status,
{'Content-Type' => 'application/vnd.api+json'},
[MultiJson.dump({errors: [json_error]}, mode: :compat)]
MultiJson.dump({errors: [json_error]}, mode: :compat)
]
end

Expand Down
2 changes: 1 addition & 1 deletion lib/api_valve/forwarder/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def initialize(original_request, original_response, options = {})

# Must return a rack compatible response array of status code, headers and body
def rack_response
[status, headers, [body]]
Rack::Response.new(body, status, headers)
end

protected
Expand Down
6 changes: 5 additions & 1 deletion lib/api_valve/middleware/error_handling.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def call(env)
@app.call(env)
rescue Exception => e # rubocop:disable Lint/RescueException
log_error e
self.class.const_get(ApiValve.error_responder).new(e).call
render_error(e).to_a
end

private
Expand All @@ -17,5 +17,9 @@ def log_error(error)
ApiValve.logger.error { "#{error.class}: #{error.message}" }
ApiValve.logger.error { error.backtrace.join("\n") }
end

def render_error(error)
self.class.const_get(ApiValve.error_responder).new(error).call
end
end
end
4 changes: 2 additions & 2 deletions lib/api_valve/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ def initialize(forwarder)
end

def call(env)
to_app.call(env)
to_app.call(env).to_a
rescue ApiValve::Error::Client, ApiValve::Error::Server => e
render_error e
render_error(e).to_a
end

delegate :add_route, to: :route_set
Expand Down
2 changes: 1 addition & 1 deletion spec/api_valve/forwarder/response_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
{'Location' => '/remote-prefix/see/other/path'}
end
let(:rack_response) { response.rack_response }
let(:headers) { rack_response[1] }
let(:headers) { rack_response.headers }

describe 'Location header' do
subject { headers['Location'] }
Expand Down
3 changes: 1 addition & 2 deletions spec/examples/middlewares_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
RSpec.describe 'Middleware example', type: :feature do
let(:builder) { example_app 'middleware' }
let(:app) { builder[0] }
let(:app) { example_app 'middleware' }

before do
stub_request(:get, %r{^http://api.host/api})
Expand Down
3 changes: 1 addition & 2 deletions spec/examples/permissions_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
RSpec.describe 'Permissions example', type: :request do
let(:builder) { example_app 'permissions' }
let(:app) { builder[0] }
let(:app) { example_app 'permissions' }

before do
stub_request(:get, %r{^http://api.host/api})
Expand Down
3 changes: 1 addition & 2 deletions spec/examples/rewriting_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
RSpec.describe 'Rewriting example', type: :feature do
let(:builder) { example_app 'rewriting' }
let(:app) { builder[0] }
let(:app) { example_app 'rewriting' }

before do
stub_request(:get, %r{^http://api.host/api})
Expand Down
22 changes: 22 additions & 0 deletions spec/examples/routing_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
RSpec.describe 'Routing example', type: :feature do
let(:app) { example_app 'routing' }

before do
stub_request(:get, %r{^http://jsonplaceholder.typicode.com/users})
.to_return(status: 204, headers: {'Content-Type' => 'application/json'})
end

describe "GET '/api/customers/1'" do
it 'correctly forwards the request' do
get '/api/customers/1'
expect(WebMock).to(have_requested(:get, 'http://jsonplaceholder.typicode.com/users/1'))
end
end

describe "GET '/api/users/2'" do
it 'correctly forwards the request' do
get '/api/users/2'
expect(WebMock).to(have_requested(:get, 'http://jsonplaceholder.typicode.com/users/2'))
end
end
end
4 changes: 3 additions & 1 deletion spec/support/helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module Helper
def example_app(example)
path = Pathname.new(__FILE__).join("../../../examples/#{example}/config.ru")
Rack::Builder.parse_file(path.to_s)
# In rack 2.x parse_file returns a tuple
app, _config = *Rack::Builder.parse_file(path.to_s)
app
end
end

0 comments on commit ddcff9d

Please sign in to comment.