Thanks to visit codestin.com
Credit goes to github.com

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
3 changes: 2 additions & 1 deletion lib/gitlab/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Gitlab
# Defines constants and methods related to configuration.
module Configuration
# An array of valid keys in the options hash when configuring a Gitlab::API.
VALID_OPTIONS_KEYS = %i[endpoint private_token user_agent sudo httparty pat_prefix].freeze
VALID_OPTIONS_KEYS = %i[endpoint private_token user_agent sudo httparty pat_prefix body_as_json].freeze

# The user agent that will be sent to the API endpoint if none is set.
DEFAULT_USER_AGENT = "Gitlab Ruby Gem #{Gitlab::VERSION}"
Expand Down Expand Up @@ -41,6 +41,7 @@ def reset
self.httparty = get_httparty_config(ENV['GITLAB_API_HTTPARTY_OPTIONS'])
self.sudo = nil
self.user_agent = DEFAULT_USER_AGENT
self.body_as_json = false
end

private
Expand Down
23 changes: 22 additions & 1 deletion lib/gitlab/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Request
headers 'Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded'
parser(proc { |body, _| parse(body) })

attr_accessor :private_token, :endpoint, :pat_prefix
attr_accessor :private_token, :endpoint, :pat_prefix, :body_as_json

# Converts the response body to an ObjectifiedHash.
def self.parse(body)
Expand Down Expand Up @@ -49,6 +49,8 @@ def self.decode(response)
params[:headers].merge!(authorization_header)
end

jsonify_body_content(params) if body_as_json

retries_left = params[:ratelimit_retries] || 3
begin
response = self.class.send(method, endpoint + path, params)
Expand Down Expand Up @@ -114,5 +116,24 @@ def authorization_header
def httparty_config(options)
options.merge!(httparty) if httparty
end

# Handle 'body_as_json' configuration option
# Modifies passed params in place.
def jsonify_body_content(params)
# Only modify the content type if there is a body to process AND multipath
# was not explicitly requested. There are no uses of multipart in this code
# today, but file upload methods require it and someone might be manually
# crafting a post call with it:
return unless params[:body] && params[:multipart] != true

# If the caller explicitly requested a Content-Type during the call, assume
# they know best and have formatted the body as required:
return if params[:headers]&.key?('Content-Type')

# If we make it here, then we assume it is safe to JSON encode the body:
params[:headers] ||= {}
params[:headers]['Content-Type'] = 'application/json'
params[:body] = params[:body].to_json
end
end
end
30 changes: 30 additions & 0 deletions spec/gitlab/request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
it { is_expected.to respond_to :post }
it { is_expected.to respond_to :put }
it { is_expected.to respond_to :delete }
it { is_expected.to respond_to :patch }

describe '.default_options' do
it 'has default values' do
Expand Down Expand Up @@ -288,4 +289,33 @@
).to have_been_made
end
end

describe 'JSON request bodies' do
subject(:request) { described_class.new }

let(:endpoint) { 'https://example.com/api/v4' }
let(:path) { '/testpath' }
let(:request_path) { "#{endpoint}#{path}" }

before do
request.private_token = 'token'
request.endpoint = endpoint
request.body_as_json = true
allow(request).to receive(:httparty) # rubocop:disable RSpec/SubjectStub

stub_request(:post, request_path).with(headers: { 'Content-Type' => 'application/json' })
end

it 'makes a request with application/json encoding when no Content-Type is specified' do
request.post(path, body: { param: 'val' })

expect(a_request(:post, request_path).with(body: { param: 'val' }.to_json)).to have_been_made
end

it 'passes the unmodified request when a Content-Type is specified' do
request.post(path, body: { param: 'val' }.to_json, headers: { 'Content-Type' => 'application/json' })

expect(a_request(:post, request_path).with(body: { param: 'val' }.to_json)).to have_been_made
end
end
end