Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ on: [push]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['3.4', '4.0']
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@477b21f02be01bcb8030d50f37cfec92bfa615b6
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true
- run: bundle install
- run: bundle exec rspec
rubocop:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@477b21f02be01bcb8030d50f37cfec92bfa615b6
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
ruby-version: '4.0'
bundler-cache: true
- run: bundle install
- run: bundle exec rubocop
1 change: 0 additions & 1 deletion .ruby-gemset

This file was deleted.

2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.2.2
4.0.1
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Changelog

## [2.0.0] - 2026-09-28

### Fixed
- The default `/` prefix was applied twice when building request paths, so a caller path that
already started with `/` produced a leading `//`. Faraday treats that as a protocol-relative URL
and mangles it, yielding malformed URLs like `https://host////api/path` that some upstream APIs
reject at the edge with a bare 403.

### Breaking Changes
- Dropped support for Ruby versions older than 3.4. Officially supported versions are Ruby 3.4 and 4.0.
- Pinned `faraday` to `~> 2.0` (previously unbounded above `2.0`).
18 changes: 4 additions & 14 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
source "http://rubygems.org"
# frozen_string_literal: true

gem 'activesupport', '>= 5.1.4'
gem 'faraday', '> 2.0'
gem 'faraday-mashify'
gem 'faraday-multipart'
source 'https://rubygems.org'

# Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc.
group :development do
gem "rspec"
gem "bundler"
gem "webmock"
gem "rspec-its"
gem "rubocop"
end
# Specify your gem's dependencies in vertebrae.gemspec
gemspec
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Some basic infrastructure for writing beautiful API clients. See tijuana\_client

[![CI Status](https://github.com/controlshift/vertebrae/actions/workflows/ci.yml/badge.svg)](https://github.com/controlshift/vertebrae/actions/workflows/ci.yml)

## Requirements

- Ruby 3.4 or 4.0
- Faraday ~> 2.0

## Development

After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests.
Expand Down
37 changes: 3 additions & 34 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,39 +1,8 @@
# encoding: utf-8
# frozen_string_literal: true

require 'rubygems'
require 'bundler'
require 'bundler/gem_tasks'


begin
Bundler.setup(:default, :development)
rescue Bundler::BundlerError => e
$stderr.puts e.message
$stderr.puts "Run `bundle install` to install missing gems"
exit e.status_code
end
require 'rake'

require 'rspec/core'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec) do |spec|
spec.pattern = FileList['spec/**/*_spec.rb']
end

desc "Code coverage detail"
task :simplecov do
ENV['COVERAGE'] = "true"
Rake::Task['spec'].execute
end

task :default => :spec

require 'rdoc/task'
Rake::RDocTask.new do |rdoc|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
RSpec::Core::RakeTask.new(:spec)

rdoc.rdoc_dir = 'rdoc'
rdoc.title = "vertebrae #{version}"
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('lib/**/*.rb')
end
task default: :spec
3 changes: 2 additions & 1 deletion lib/vertebrae/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ def request(method, path, params, options) # :nodoc:
end
connection.options = default_options.merge(initialisation_options.merge(options))

path = connection.configuration.prefix + '/' + path
# Avoid a leading '//' here — Faraday treats it as a protocol-relative URL and mangles the path.
path = File.join(connection.configuration.prefix.to_s, path.to_s.delete_prefix('/'))

::Vertebrae::Base.logger.debug "EXECUTED: #{method} - #{path} with #{params} and #{options}"

Expand Down
2 changes: 1 addition & 1 deletion lib/vertebrae/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module Vertebrae
VERSION = '1.0.5'
VERSION = '2.0.0'
end
16 changes: 16 additions & 0 deletions spec/request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@
end
end

context 'with a custom prefix and a path without a leading slash' do
let(:options) { {prefix: '/rest/v1'} }
it 'should join the prefix and path with a single slash' do
stub_request(:get, 'https://test.com/rest/v1/user/')
vb.request(:get, 'user/', {}, options)
end
end

context 'with the default prefix and an already-absolute path' do
let(:options) { {} }
it 'should not produce a malformed URL with duplicate slashes' do
stub_request(:post, 'https://test.com/api/member/details')
vb.request(:post, '/api/member/details', {}, options)
end
end

context 'with a different host' do
let(:options) { {host: 'test2.com'} }
it 'should make the request to the default host' do
Expand Down
62 changes: 31 additions & 31 deletions vertebrae.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,45 @@ lib = File.expand_path('lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'vertebrae/version'

Gem::Specification.new do |s|
s.name = "vertebrae".freeze
s.version = Vertebrae::VERSION

s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
s.require_paths = ["lib".freeze]
s.authors = ["Nathan Woodhull".freeze]
s.date = "2021-07-23"
s.description = "A set of low level infrastructure and reusable code for building API clients".freeze
s.email = "nathan@controlshiftlabs.com".freeze
s.extra_rdoc_files = [
"LICENSE.txt",
"README.md"
Gem::Specification.new do |spec|
spec.name = 'vertebrae'
spec.version = Vertebrae::VERSION
spec.authors = ['Nathan Woodhull', 'Owens Ehimen']
spec.email = ['talk@controlshiftlabs.com']

spec.summary = 'API Client Infrastructure'
spec.description = 'A set of low level infrastructure and reusable code for building API clients'
spec.homepage = 'https://github.com/controlshift/vertebrae'
spec.license = 'MIT'

spec.extra_rdoc_files = [
'LICENSE.txt',
'README.md'
]

# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
s.files = Dir.chdir(File.expand_path(__dir__)) do
spec.files = Dir.chdir(File.expand_path(__dir__)) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.require_paths = ['lib']

s.homepage = "http://github.com/controlshift/vertebrae".freeze
s.licenses = ["MIT".freeze]
s.summary = "API Client Infrastructure".freeze
spec.required_ruby_version = ['>= 3.4', '< 5.0']

if s.respond_to? :specification_version then
s.specification_version = 4
end
# Runtime dependencies
spec.add_runtime_dependency 'activesupport', '>= 6.1'
spec.add_runtime_dependency 'faraday', '~> 2.0'
spec.add_runtime_dependency 'faraday-mashify', '~> 1.0'
spec.add_runtime_dependency 'faraday-multipart', '~> 1.0'

# Development dependencies
spec.add_development_dependency 'bundler', '>= 2.0', '< 5.0'
spec.add_development_dependency 'rake', '~> 13.0'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'rspec-its', '~> 2.0'
spec.add_development_dependency 'rubocop', '~> 1.0'
spec.add_development_dependency 'webmock', '~> 3.0'

s.add_runtime_dependency(%q<activesupport>.freeze, [">= 5.1.4"])
s.add_runtime_dependency(%q<faraday>.freeze, ["~> 2"])
s.add_runtime_dependency(%q<faraday-mashify>.freeze, [">= 0"])
s.add_runtime_dependency(%q<faraday-multipart>.freeze, [">= 0"])

s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
s.add_development_dependency(%q<webmock>.freeze, [">= 0"])
s.add_development_dependency(%q<rspec-its>.freeze, [">= 0"])
s.add_development_dependency(%q<juwelier>.freeze, [">= 0"])
s.add_development_dependency(%q<rubocop>.freeze, [">= 0"])
spec.metadata['rubygems_mfa_required'] = 'true'
end

Loading